elanous 0.2.22 → 0.2.24
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/NOTICE +7 -0
- package/README.md +32 -22
- package/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/{aBi6EyMtLsrl7J8eH4kF7 → Q-7iofoxOEv1WX18S35of}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/{119fc678.6f591cdb84ca5791.js → 0673cc54.8e2ef1c23e49e190.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{a9f2b54d-40c16bd0efdb04b8.js → 0a09e062-34f747a17d8d8c2e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{f8626309.a4e5d362b1d55e59.js → 0e3acd34.d42b2ef87fdf4234.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1168.a0fb3d9db76c00bd.js +77 -0
- package/apps/pwa/out/_next/static/chunks/{7175-350f4ce2873bc038.js → 1325-dc3f3c21eb181cb4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1357.a843c41d2cd7ec31.js +34 -0
- package/apps/pwa/out/_next/static/chunks/1430.53f49882b17607c2.js +24 -0
- package/apps/pwa/out/_next/static/chunks/1459-be6509b3419d8a9f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6767.8e6c5f6e744fcd9f.js → 1505.5826671109111e75.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/153.0a4e3cd516930491.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1572.7bc291352e241a45.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1593-d07ad068c120dfb0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1608.b7c900baa56cab32.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1615-4d8156febaac4b35.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1646.e03f0fbc26bc72f6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7327-2d69fb321ba73389.js → 1669-da843ed73aa301f5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/176.13ba0659e3e96fd4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1990.9c60f495ef33c070.js +36 -0
- package/apps/pwa/out/_next/static/chunks/2042e469.f86158dd5c1e51a1.js +122 -0
- package/apps/pwa/out/_next/static/chunks/2528.0af5c0e1fad88df6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2543-28ec6aeb80a5e1e1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2561.43c99d6ee914ee6a.js +62 -0
- package/apps/pwa/out/_next/static/chunks/2638.b39ab2f674caa1a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/272-0eed0fb0aab716b6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7899.597af4a9996c907f.js → 2721.bc9a8f36bd85c07a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2778.67e0c1d484189ccf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2841.10ff309f6a3168af.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2886-9639f97d523d752a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2978.57fb87ce21cc5a85.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3664.15f968c39d15bd28.js +149 -0
- package/apps/pwa/out/_next/static/chunks/3786-935eb3fcde90e496.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3813.df4a01ae89c6f63f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3961-aaae04ed1d32622f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3992.f79c70480e8c4077.js +309 -0
- package/apps/pwa/out/_next/static/chunks/40-413e8641de9ed1e5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4054-521f11a503daed64.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4315.e7356f34c7d8ec79.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4489-bf629de6f04f7681.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4540.557733cc88c6a82b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/462.0275b4338c5b6337.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4658-7ed9266098a787e4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4945-0f4046cfc3228ea3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{d70879db.c66c56a95a91efc6.js → 4c5e95ce.83e9b16add6fcd8c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5105-18b4165c5d3a86b0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5205-6992210fe31f45f4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5287-72898b126d722457.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6158.566c890adc06a459.js → 5313.1697309c532b9856.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{79b78388.663188133449d707.js → 53746282.1be36038d1abd949.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5474.991b90688c3cb321.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5544-871146192d095594.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5578.ac963634373b28c6.js +286 -0
- package/apps/pwa/out/_next/static/chunks/5935.d5e8ca3e096772e8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5967-c0a80f8ffe5d4050.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1268.0840ff91e083fcbd.js → 5974.360f8441eb0ac1ec.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6006.84e8b418a7a0db97.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6013-1267ba7454d6764b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6038-1e0f7ee1086da4cf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/617.709dd0019fe99796.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6261.fb9bf94947094636.js +74 -0
- package/apps/pwa/out/_next/static/chunks/6411.1966866fae31ffa9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6481-b829d99aa8d158f5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6541.2b7daa043100d0fa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6571-926ddf024a6ad5df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6597.2d7a6d77ab485b27.js +64 -0
- package/apps/pwa/out/_next/static/chunks/67.5dd2dc543c2fa3de.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9832.2ab2e818013574c7.js → 6702.ebbd165d5e4a4a14.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6777-312496b0d774719b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/681.0116f7036cfb4e8d.js +32 -0
- package/apps/pwa/out/_next/static/chunks/6871.30b2bf23b3126e36.js +24 -0
- package/apps/pwa/out/_next/static/chunks/6882.737d366d54e29d83.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7035.54c2c535164b1c9b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7086-8bfa7e8f796a03d9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7126.5e5599f251726b67.js +93 -0
- package/apps/pwa/out/_next/static/chunks/7203-47ff0740a293e284.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7268.017f49dafb5f0ff3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7355.5d65a87e9567ae08.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7392.4018c2a62177f296.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6110.1297d4093fdfbb0d.js → 740.90b31555290236a9.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/7471.3a3d1be50559cfb8.js +148 -0
- package/apps/pwa/out/_next/static/chunks/7500.73489a345cef2201.js +226 -0
- package/apps/pwa/out/_next/static/chunks/{9070.067c106528ec1ae6.js → 7518.49161e8f5814abdb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7565.c2f72a15c1ed0396.js +27 -0
- package/apps/pwa/out/_next/static/chunks/7651.6d1c984d3d8587a4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7713.7ab863ed59b2d661.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7793.d7cd2026767ddd54.js +115 -0
- package/apps/pwa/out/_next/static/chunks/7837.c7c267e5dceadb11.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7891.09266382daf70d1c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7905.b230b9d06cb4ad5d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7990-cbf6a01bcbdcb7e6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8119-819c549e0c197786.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8186-74ea19a3700d04a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8194.484f51e273d9abd2.js → 8264.00e434fbd02e9311.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/8267-e7b3262b735ae106.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8386.86518e55b75f7cf5.js +8 -0
- package/apps/pwa/out/_next/static/chunks/{088d8e8a.8069543d082bec12.js → 83cfc5c8.349535543c1548b6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8437.ba6eeeb29590042f.js +23 -0
- package/apps/pwa/out/_next/static/chunks/{1948.5f35b39eef222a94.js → 8438.ee7f0df3b3f6fcb4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8469-1500be57e582296f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8483-7164cecdaf178ca6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4588.ad3364cb7fb97ada.js → 8532.a86e99acf9b761cb.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/8569.b853a8daa8f31d12.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8722-4c940f02c496ad36.js +1 -0
- package/apps/pwa/out/_next/static/chunks/887-41d0dcf5af48c628.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8925-2abfb48af477fb7f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{88729267.9c6c000157c83f2f.js → 89849432.9eaa2f4c9c010965.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/9039.da86361496797522.js +90 -0
- package/apps/pwa/out/_next/static/chunks/905.d5745a25884754d4.js +94 -0
- package/apps/pwa/out/_next/static/chunks/9089-d909f3d4478b0628.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9096.dc5c7a267f83790c.js +41 -0
- package/apps/pwa/out/_next/static/chunks/93.a567257b6bdb7fe4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9320.419acb9665b46597.js +287 -0
- package/apps/pwa/out/_next/static/chunks/9356.b8ceda6634612ff8.js +79 -0
- package/apps/pwa/out/_next/static/chunks/94.e9e1043b35cd3eed.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9400-7498ea90b2e6ee8f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3522-1de1319d028ac89c.js → 9502-32c5dc22e8f120f5.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/9930-58644af9c813d6e1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9932.367cf4725fedd6e2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9935.1628b904cdc8ce0e.js +104 -0
- package/apps/pwa/out/_next/static/chunks/{7630.2b9a68659053ff4e.js → 9976.8f28864317639fe6.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-a2aa8709d193ee0d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-3b9fc39362473ae7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-f2b62c19ca68fef8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-d7602d489edf5f37.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-24282bf9f90031a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-8b7c5ab6b5bc8d64.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-4eb84d454f8c3415.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-b2e494bdad57fcb5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/{page-80ed511e02c81412.js → page-c0ab229673a8b0eb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-3e2b45f3c36dbac4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-c22aa511b28743ad.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-26345242e4049f55.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-bf88c0f558d8ef54.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-52fec523e5b5d3ad.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-67723dfdcde92b31.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-a2aa8709d193ee0d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-22725e2570f1126b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-1891335950d68b70.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-3267af1ebdc73cf5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-c314b75c11234998.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-9f9c85415f61782b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-c1d4276059085587.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-833aab587f26ad4c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-8526c17ae38e6a50.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-f998637a8402115c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-b7bb53828b17b335.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-1b1850de0257e46d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-6f23159fedb41f67.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-1d809a87139dd024.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-da9e570234d481fd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-b92caddb5c715f30.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-8ce3a38e210b810a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-57ffeeb6019440fd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-abbb417bf514630b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-2c2b3f29cec1efa4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-9369279f72fc7b51.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-64861f14039499c3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-ddc4c93efd8ab94b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-a2aa8709d193ee0d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-901a1391b81053bc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-68d9bbaac9841a58.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-b5c0c996f329371e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-89881ccbcf728978.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-0e87a803b3d7165e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-58d4e5cb30ef4871.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-02ce4c3b5f39e4d2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-e620d1bb8eadcec2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-acf868c64d77f950.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-54fa605fa6dba457.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-bc79f0833533fa84.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-d5c4398eea03d8f3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/b4e12462-5fab4a813a63dadd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/cd39fa05.fac4545f42a3ef70.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{f6b7c9ba.64a895b8b2fedbdc.js → ce383d63.d2ede338788ed18e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{framework-5c169757551134ed.js → framework-b2763b10dc6b3836.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/main-app-27893e93b0ec193d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-f280047194e1daf8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-e90eff2d0b70564c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-70f2d654b3435d34.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-4794f053bd5e4230.js +1 -0
- package/apps/pwa/out/_next/static/css/72becfd42807b50d.css +1 -0
- package/apps/pwa/out/_next/static/css/d0a48dc099ed86cf.css +1 -0
- 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 +24 -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 +24 -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/catalog/models/anthropic/claude-haiku-5-5.yaml +32 -0
- package/catalog/models/anthropic/claude-opus-5-5.yaml +5 -0
- package/catalog/models/anthropic/claude-sonnet-5-5.yaml +31 -0
- package/catalog/models/anthropic/claude-sonnet-5.yaml +8 -2
- package/catalog/models/openai/gpt-6-astra.yaml +6 -0
- package/catalog/models/openai/gpt-6-luna.yaml +6 -0
- package/catalog/models/openai/gpt-6-sol.yaml +6 -0
- package/catalog/models/openrouter/deepseek-v4-pro-0813.yaml +39 -0
- package/catalog/models/openrouter/deepseek-v4.1-flash.yaml +38 -0
- package/catalog/models/openrouter/glm-5.3-flash.yaml +35 -0
- package/catalog/providers/openrouter.yaml +2 -0
- package/graphs/implement-loop.yaml +31 -0
- package/graphs/log-horizon/log-horizon-watch.yaml +25 -0
- package/graphs/log-horizon/recipes.yaml +3 -0
- package/graphs/ops/harness-gc.yaml +17 -0
- package/graphs/ops/recipes.yaml +3 -0
- package/graphs/overlays/README.md +1 -1
- package/graphs/overlays/stop-heal-ladder.yaml +105 -0
- package/graphs/release/recipes.yaml +1 -1
- package/graphs/release/release-loop.yaml +6 -2
- package/graphs/release-rehearsal/recipes.yaml +12 -0
- package/graphs/release-rehearsal/release-rehearsal.yaml +17 -0
- package/package.json +4 -1
- package/scripts/add-api-key.sh +1 -1
- package/scripts/bench-report.ts +82 -3
- package/scripts/ci-typecheck-changed.ts +80 -14
- package/scripts/fleet/bedrock-pod-secret.ts +122 -0
- package/scripts/fleet/node-setup-linux.sh +97 -0
- package/scripts/fleet/node-setup.sh +11 -0
- package/scripts/fleet/zai-pod-secret.ts +86 -0
- package/scripts/hq/hq-fence-wrapper.sh +148 -0
- package/scripts/land-global-checks.ts +3 -0
- package/scripts/lib/typecheck-ratchet.ts +51 -0
- package/scripts/measure-log-diet-2.ts +213 -0
- package/scripts/measure-tsc-affected-roots.ts +289 -0
- package/scripts/openai-relay-server.ts +5 -1
- package/scripts/release-loop/docs-node.ts +258 -43
- package/scripts/release-loop/gate-executor.ts +28 -0
- package/scripts/release-loop/gate-method.ts +59 -0
- package/scripts/release-loop/gate-node.ts +335 -33
- package/scripts/release-loop/gate-wall.ts +208 -0
- package/scripts/release-loop/known-issues-node.ts +53 -8
- package/scripts/release-loop/publish-at.ts +14 -0
- package/scripts/release-loop/publish-node.ts +17 -2
- package/scripts/release-loop/resume-release.ts +40 -4
- package/scripts/release-loop/resume.ts +94 -0
- package/scripts/release-loop/shard-plan.ts +3 -11
- package/scripts/release-loop/tui-node-checks.ts +22 -0
- package/scripts/release-loop/unattended-release.ts +29 -7
- package/scripts/rhythm/daily.ts +51 -2
- package/scripts/rhythm/weekly.ts +3 -2
- package/scripts/tsc-baseline-cache.ts +147 -0
- package/scripts/tsc-main-safety-net.ts +189 -0
- package/scripts/usage-rollup.ts +64 -8
- package/src/acp/codex-plugins.ts +48 -6
- package/src/agent/monad-agent-turn.ts +67 -5
- package/src/agent/run-context.ts +20 -0
- package/src/agent/tool-profile.ts +28 -2
- package/src/agent-mission/acp-judge.ts +8 -2
- package/src/agent-mission/capabilities-cli.ts +16 -1
- package/src/agent-mission/driver.ts +19 -4
- package/src/agent-mission/pr-review-watch.ts +6 -2
- package/src/agent-mission/resource-ladder.ts +8 -3
- package/src/agent-mission/review-loop.ts +41 -7
- package/src/agent-substrate/acp-implementer.ts +139 -0
- package/src/agent-substrate/acp-reviewer.ts +17 -8
- package/src/agent-substrate/pr-reviewer.ts +191 -28
- package/src/agent-substrate/review-intent.ts +6 -4
- package/src/agent-substrate/self-review-cli.ts +155 -21
- package/src/agent-substrate/shard-boundary-intent.ts +92 -26
- package/src/ask-user-question/pending-questions.ts +8 -2
- package/src/autopilot/build/llm-conflict-merge.ts +216 -12
- package/src/autopilot/codebase-grounding.ts +44 -0
- package/src/autopilot/llm-control-brain.ts +13 -1
- package/src/autopilot/mission-codebase-gate.ts +8 -77
- package/src/autopilot/mission-critique.ts +18 -5
- package/src/autopilot/mission-feasibility-negotiate.ts +11 -10
- package/src/autopilot/mission-trace.ts +12 -1
- package/src/autopilot/pr-manager.ts +12 -3
- package/src/autopilot/system-lookback-run.ts +16 -10
- package/src/bench/bench.ts +183 -0
- package/src/boot/acp-server.ts +4 -7
- package/src/boot/acp-socket-path.ts +7 -0
- package/src/briefing/brief-items.ts +21 -13
- package/src/budget/fetchers/grok.ts +15 -5
- package/src/budget/llm-cost.ts +37 -5
- package/src/budget/types.ts +8 -2
- package/src/budget/unified-usage.ts +88 -6
- package/src/chat/index.ts +12 -3
- package/src/cli/agent-cli.ts +20 -0
- package/src/cli/bench-cli.ts +34 -0
- package/src/cli/brief-cli.ts +27 -21
- package/src/cli/cli-user-error.ts +9 -2
- package/src/cli/guardian-cli.ts +26 -1
- package/src/cli/image-cli.ts +101 -0
- package/src/cli/log-event-names.ts +7 -0
- package/src/cli/logs-cli.ts +1 -0
- package/src/cli/mcp-login.ts +111 -37
- package/src/cli/plugin-cli.ts +21 -1
- package/src/cli/pod-cli.ts +26 -0
- package/src/cli/pr-cli.ts +90 -5
- package/src/cli/pr-land-overlap-evidence.ts +279 -0
- package/src/cli/release-cli.ts +63 -12
- package/src/cli/rfc-status.ts +52 -2
- package/src/cli/self-update.ts +277 -10
- package/src/cli/skills-cli.ts +12 -3
- package/src/cli/tasks-cli.ts +241 -30
- package/src/cli/usage-cli.ts +91 -8
- package/src/context-bus/context-first.ts +51 -2
- package/src/context-bus/context-now-surfaces.ts +13 -2
- package/src/context-bus/long-term-memory.ts +3 -1
- package/src/context-bus/nightly-condense.ts +3 -2
- package/src/core-turn/run-goal-loop.ts +87 -2
- package/src/dashboard/ad-run-setup-bindings.ts +279 -0
- package/src/dashboard/chat-fold.ts +20 -0
- package/src/dashboard/first-screen-band.ts +151 -1
- package/src/dashboard/index.ts +45 -281
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +5 -3
- package/src/dashboard/stale-install-check.ts +24 -2
- package/src/dashboard/turn-stream-formatter.ts +25 -0
- package/src/debug/log-diet.ts +190 -0
- package/src/debug/log.ts +70 -17
- package/src/display/coordinator.ts +25 -2
- package/src/domains/coo-admin-tool.ts +27 -0
- package/src/domains/cron-match.ts +1 -0
- package/src/domains/outbound-alert.ts +17 -6
- package/src/domains/release-tool.ts +158 -10
- package/src/domains/schedule-registry.ts +10 -7
- package/src/domains/schedule-runner.ts +1 -0
- package/src/elanous-config-dir.ts +2 -2
- package/src/elanous-daemon.ts +3 -3
- package/src/error-report/report.ts +21 -4
- package/src/execution-loop/launch-gate.ts +1 -1
- package/src/expression/i18n/messages.en.ts +5 -0
- package/src/expression/i18n/messages.ja.ts +5 -0
- package/src/expression/i18n/messages.ko.ts +5 -0
- package/src/expression/i18n/messages.zh.ts +5 -0
- package/src/expression/i18n/types.ts +8 -0
- package/src/github/pr-labels.ts +2 -0
- package/src/graph-runner/graph-cli.ts +42 -1
- package/src/graph-runner/runner.ts +218 -8
- package/src/grok/usage.ts +23 -2
- package/src/grounding/ref-index.ts +253 -0
- package/src/harness/dispatch-backpressure.ts +267 -0
- package/src/harness/harness-clean.ts +199 -78
- package/src/harness/harness-cli-command.ts +229 -35
- package/src/harness/harness-gc.ts +331 -0
- package/src/harness/harness-seams.ts +2 -20
- package/src/harness/harness-stop.ts +4 -2
- package/src/harness/harness-substrate-default.ts +214 -8
- package/src/harness/launch-registry.ts +6 -0
- package/src/harness/nested-elanous-policy.ts +4 -2
- package/src/harness/worktree-branch-prefix.ts +9 -0
- package/src/hq/fence-wrapper.ts +7 -0
- package/src/hq/fence.ts +187 -0
- package/src/hq/hq.ts +33 -2
- package/src/hq/lease.ts +13 -0
- package/src/hq/seats.ts +133 -21
- package/src/images/image-ledger.ts +179 -0
- package/src/index.ts +250 -69
- package/src/instance/child-scope.ts +32 -1
- package/src/instance/dev-project.ts +133 -0
- package/src/instance/resolve.ts +24 -0
- package/src/instance/spawn-elanous.ts +45 -0
- package/src/intake-plane/collect-github.ts +19 -1
- package/src/intake-plane/digest.ts +45 -20
- package/src/intake-plane/lens.ts +36 -8
- package/src/intake-plane/ref-prefetch.ts +110 -0
- package/src/intelligence-map/model-alias.ts +6 -0
- package/src/intelligence-map/model-catalog.ts +113 -0
- package/src/knowledge/kgs/pack.ts +5 -2
- package/src/knowledge/kgs/sqlite-store.ts +15 -0
- package/src/knowledge/tools/knowledge-query.ts +20 -2
- package/src/knowledge/write.ts +234 -2
- package/src/llm/bedrock-eventstream.ts +215 -0
- package/src/llm/bedrock-provider.ts +248 -0
- package/src/llm/bedrock.ts +491 -0
- package/src/llm/openrouter-byok-cost.ts +96 -0
- package/src/llm/openrouter-deepseek.ts +151 -0
- package/src/llm/openrouter-upstream-pins.config.ts +25 -0
- package/src/llm/provider-credentials.ts +3 -1
- package/src/llm/zai-coding-plan.ts +700 -0
- package/src/llm.ts +383 -41
- package/src/loops/budget.ts +150 -0
- package/src/loops/checker.ts +148 -9
- package/src/loops/orchestrator/resync-shadow.ts +34 -7
- package/src/loops/orchestrator/seat-share.ts +6 -49
- package/src/loops/orchestrator/traffic.ts +5 -81
- package/src/market/signed-index.ts +42 -0
- package/src/maturity/feature-maturity.ts +2 -2
- package/src/mcp/mcp-oauth.ts +136 -17
- package/src/model-tier/llm-tier-map.ts +52 -4
- package/src/models/prompts.ts +23 -1
- package/src/mss/logging/horizon-watch.ts +168 -0
- package/src/mss/logging/log-store.ts +262 -26
- package/src/native-tool-catalog.ts +1 -1
- package/src/nexus/api/consult-requests.ts +7 -10
- package/src/nexus/api/discord-trigger-bot.ts +6 -3
- package/src/nexus/api/error-reports.ts +30 -8
- package/src/nexus/api/http-server.ts +8 -0
- package/src/nexus/api/loop-resources.ts +42 -0
- package/src/nexus/api/missions.ts +73 -2
- package/src/nexus/api/ops-api.ts +18 -0
- package/src/nexus/api/outbound-report.ts +8 -3
- package/src/nexus/api/telegram-trigger-bot.ts +6 -3
- package/src/nexus/index.ts +17 -75
- package/src/nexus/outbound/format.ts +2 -0
- package/src/nexus/outbound/router.ts +198 -13
- package/src/nexus/tools-kind.ts +78 -0
- package/src/oauth/codex-account-rotation.ts +55 -20
- package/src/oauth/codex-account-store.ts +451 -23
- package/src/oauth/fallback-chain.ts +75 -15
- package/src/onboarding/first-run.ts +37 -18
- package/src/onboarding/web-first.ts +20 -2
- package/src/onboarding.ts +2 -1
- package/src/ops/machine-heartbeat.ts +185 -0
- package/src/ops/overview-cache.ts +175 -0
- package/src/ops/overview.ts +8 -0
- package/src/plugins/adapters/claude-package.ts +4 -12
- package/src/plugins/core/capability-policy.ts +141 -0
- package/src/plugins/core/host.ts +21 -8
- package/src/plugins/core/manifest.ts +19 -2
- package/src/plugins/core/trust-store.ts +15 -0
- package/src/plugins/core/types.ts +12 -0
- package/src/plugins/install/market-fetch.ts +68 -16
- package/src/plugins/install/plugin-install.ts +187 -16
- package/src/plugins/maker/plugin-maker.ts +25 -20
- package/src/plugins/maker/wizard-generate.ts +16 -2
- package/src/policy/llm-policy.ts +14 -1
- package/src/process/pid-liveness.ts +1 -1
- package/src/prompt-cache/openai.ts +13 -6
- package/src/prompt-cache/openrouter.ts +94 -0
- package/src/prompt-cache/types.ts +5 -0
- package/src/prompt-enhance/enhance.ts +69 -5
- package/src/prompt-library/family-prompt-coverage.ts +1 -0
- package/src/prompt-library/universal-preamble.ts +2 -2
- package/src/registry/discovery/openrouter-live-resolve.ts +122 -0
- package/src/registry/loader.ts +6 -1
- package/src/release-loop/checklist.ts +24 -9
- package/src/release-loop/feature-store.ts +3 -0
- package/src/release-loop/gate-shards.ts +48 -4
- package/src/release-loop/landed-to-green.ts +81 -0
- package/src/release-loop/light-rc.ts +11 -1
- package/src/release-loop/merged-pr-checklist.ts +10 -0
- package/src/release-loop/placement.ts +107 -23
- package/src/release-loop/rehearsal.ts +317 -0
- package/src/release-loop/release-schedule.ts +13 -1
- package/src/release-loop/rubric-types.ts +1 -0
- package/src/release-loop/rubric.ts +2 -2
- package/src/requirements/requirement-ledger.ts +536 -0
- package/src/retro/daily.ts +26 -12
- package/src/seat-loop/seat-loop.ts +66 -11
- package/src/seat-loop/traffic-signal.ts +44 -0
- package/src/self-dev/ask-launch-flow.ts +2 -2
- package/src/self-dev/dev-cli.ts +109 -11
- package/src/self-dev/dev-pipeline.ts +11 -8
- package/src/self-dev/draft-residue.ts +475 -0
- package/src/self-dev/draft-sweep.ts +254 -10
- package/src/self-dev/draft-triage-rules.ts +27 -1
- package/src/self-dev/graph-journey-route.ts +6 -0
- package/src/self-dev/launch-preflight-text.ts +549 -0
- package/src/self-dev/launch-preflight.ts +10 -545
- package/src/self-dev/orchestrate-cli.ts +82 -5
- package/src/self-dev/orchestrate-summary-line.ts +13 -0
- package/src/self-dev/orchestrate.ts +49 -141
- package/src/self-dev/review-provider-fallback.ts +115 -19
- package/src/self-dev/run-store.ts +1 -3
- package/src/self-dev/run-supervisor.ts +190 -36
- package/src/self-dev/run-types.ts +191 -0
- package/src/self-dev/shard-aggregate.ts +61 -13
- package/src/self-dev/shard-plan.ts +5 -1
- package/src/self-dev/shard-run.ts +23 -5
- package/src/self-dev/supervisor-verdict-edges.ts +3 -4
- package/src/self-implement/blocked-draft-policy.ts +3 -19
- package/src/self-implement/budget-gate.ts +53 -13
- package/src/self-implement/child-context-composition.ts +139 -0
- package/src/self-implement/child-llm-preference.ts +13 -5
- package/src/self-implement/claude-acp-implement.ts +67 -0
- package/src/self-implement/draft-on-stop-mode.ts +18 -0
- package/src/self-implement/flex-signals.ts +59 -0
- package/src/self-implement/follow-up-goals.ts +114 -38
- package/src/self-implement/frozen-merges.ts +8 -3
- package/src/self-implement/gate-baseline-reap.ts +157 -0
- package/src/self-implement/gate-baseline.ts +78 -16
- package/src/self-implement/gate-cli.ts +12 -2
- package/src/self-implement/gate-remote.ts +17 -6
- package/src/self-implement/goal-author-decompose.ts +10 -2
- package/src/self-implement/goal-author.ts +48 -13
- package/src/self-implement/goal-digest.ts +19 -0
- package/src/self-implement/graph-overlay-condition.ts +32 -0
- package/src/self-implement/graph-overlay-yaml.ts +41 -7
- package/src/self-implement/graph-templates.ts +33 -1
- package/src/self-implement/graph-yaml.ts +56 -0
- package/src/self-implement/headless-elanous-driver.ts +11 -9
- package/src/self-implement/heal-intake.ts +5 -1
- package/src/self-implement/host-regate.ts +120 -29
- package/src/self-implement/l8-merge-queue.ts +67 -5
- package/src/self-implement/merge-train.ts +131 -0
- package/src/self-implement/off-diff-evidence.ts +9 -0
- package/src/self-implement/orchestrator.ts +271 -25
- package/src/self-implement/review-finding-recurrence.ts +28 -0
- package/src/self-implement/rework-policy.ts +2 -1
- package/src/self-implement/round-summary-card.ts +63 -0
- package/src/self-implement/run-ledger.ts +4 -3
- package/src/self-implement/run-step-projection.ts +147 -0
- package/src/self-implement/run-stop.ts +1 -1
- package/src/self-implement/running-runs.ts +75 -5
- package/src/self-implement/seams.ts +83 -4
- package/src/self-implement/self-implement-cli.ts +12 -5
- package/src/self-implement/stop-autoheal.ts +69 -2
- package/src/self-implement/train-gate-remote.ts +158 -0
- package/src/session-runtime/index.ts +10 -1
- package/src/session-runtime/retry-api.ts +11 -1
- package/src/session-runtime/retry-policy.ts +2 -1
- package/src/skills/gift-install.ts +119 -0
- package/src/skills/runner.ts +59 -2
- package/src/skills/skill-feedback.ts +31 -1
- package/src/skills/skill-tier.ts +1 -0
- package/src/smart-wizard/capability-index.ts +231 -0
- package/src/smart-wizard/rung.ts +74 -0
- package/src/steward/launch.ts +22 -10
- package/src/steward/triage-budget.ts +62 -0
- package/src/steward/triage.ts +87 -24
- package/src/storage/file-lock.ts +8 -1
- package/src/task-agent/actions.ts +66 -5
- package/src/task-agent/card-evidence.ts +59 -13
- package/src/task-agent/completion-evidence.ts +5 -0
- package/src/task-agent/cover.ts +101 -3
- package/src/task-agent/judge.ts +20 -3
- package/src/task-agent/land-order-ledger.ts +95 -0
- package/src/task-agent/land-worktree.ts +201 -0
- package/src/task-agent/live-move-history.ts +219 -0
- package/src/task-agent/live-moves.ts +451 -34
- package/src/task-agent/parent-host.ts +117 -8
- package/src/task-agent/rejudge-on-head.ts +352 -0
- package/src/task-agent/review-prior-fix.ts +146 -0
- package/src/task-agent/review-result-capture.ts +218 -0
- package/src/task-agent/run-adopt.ts +136 -0
- package/src/task-agent/shadow.ts +154 -14
- package/src/task-agent/task-hand.ts +186 -14
- package/src/task-orchestrator/surfaces/pod-account-broker.ts +38 -5
- package/src/task-orchestrator/surfaces/pod-bedrock-child.ts +74 -0
- package/src/task-orchestrator/surfaces/pod-child-default.ts +50 -0
- package/src/task-orchestrator/surfaces/pod-child-providers.ts +42 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +6 -3
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +94 -7
- package/src/task-orchestrator/surfaces/pod-image-source.ts +212 -0
- package/src/task-orchestrator/surfaces/pod-lease.ts +110 -17
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +32 -3
- package/src/task-orchestrator/surfaces/pod-pool.ts +86 -18
- package/src/task-orchestrator/surfaces/pod-zai-child.ts +101 -0
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +463 -50
- package/src/task-orchestrator/surfaces/self-implement.ts +25 -3
- package/src/telegram-service.ts +5 -1
- package/src/telegram.ts +17 -4
- package/src/time/format.ts +13 -4
- package/src/tool-runtime/goal-author-runtime.ts +1 -0
- package/src/tool-runtime/self-cognition-catalog.ts +23 -0
- package/src/tool-runtime/self-cognition-runtimes.ts +2 -24
- package/src/typecheck-ratchet.ts +1 -0
- package/src/user-config.ts +180 -32
- package/src/ux-sim/slash-menu-frames.ts +168 -0
- package/src/version/packed-revision.json +1 -1
- package/src/web-terminal/preview-tap-registry.ts +5 -2
- package/src/workflow-runtime/triggers/registry.ts +59 -0
- package/src/workflow-runtime/triggers/scheduler.ts +1 -0
- package/src/workflow-runtime/triggers/webhook-source.ts +35 -5
- package/apps/pwa/out/_next/static/chunks/1109.78a7a3288c0259d9.js +0 -148
- package/apps/pwa/out/_next/static/chunks/115.1c6690b8604f81c4.js +0 -32
- package/apps/pwa/out/_next/static/chunks/1262.76a3f08e67c5f816.js +0 -309
- package/apps/pwa/out/_next/static/chunks/1307-08b716476f1d50af.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1358d292.5c87f12cad6eaa91.js +0 -122
- package/apps/pwa/out/_next/static/chunks/1438.27a1a7b8f2308004.js +0 -149
- package/apps/pwa/out/_next/static/chunks/1442.02d85cd88f4c1eac.js +0 -79
- package/apps/pwa/out/_next/static/chunks/1501-1aad662d82ba43f7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1584.9e2dd53da6e6d4b1.js +0 -24
- package/apps/pwa/out/_next/static/chunks/1586.b989b0614afb77e6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1609.2ad355062870151f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1612-f6df0fc0eed7157b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1826-5d279da64bbbc2de.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1923.37f1d5fe7ebe3860.js +0 -27
- package/apps/pwa/out/_next/static/chunks/195-fb1d7690bf30bab4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1986-33e13d648a9df765.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1993.3fd074a2a246234e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/211-9c9090c59e2c5907.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2140.d2daf9ee96e295d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2212.0359851457473efc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/224.583e562365a52f74.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2328.0f37465646bafa7d.js +0 -36
- package/apps/pwa/out/_next/static/chunks/2372.bf71372184991937.js +0 -286
- package/apps/pwa/out/_next/static/chunks/2489-d238d3e2eb5b2bf5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2537-6c289376caa88ca1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2549-a8515c86f9e8cb96.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2655.72cc6a97276c5acc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2699-325cc923ba7b8631.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2743-ef6e8c3ced74cce5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2840-5458ad50c49cac6a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2856.f75d5baef7f49b74.js +0 -1
- package/apps/pwa/out/_next/static/chunks/311.e685738f92e6e2ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3344.0de4b0ec5a454b7a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/335.a13f339e97893437.js +0 -94
- package/apps/pwa/out/_next/static/chunks/3394.646348f34b2500be.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3443.6276909b53d72d53.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3495.abd4254d808bf2dc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3558-bbb5ab553a0471d3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3721.ba5b82db0d9a5572.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3857-5985236d9307f676.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3919.9ff7dc25afefee33.js +0 -74
- package/apps/pwa/out/_next/static/chunks/3998.bd9a69d9b50e9bd2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4003.ab6db1dc266576c9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4144-fad095b48a1862ee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4216.e8ac94b9fe6b96ab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4327.c44dc2b55cb43ee5.js +0 -34
- package/apps/pwa/out/_next/static/chunks/4401.94257d497b6d26bc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4559.17ca2cdbaa8d414f.js +0 -115
- package/apps/pwa/out/_next/static/chunks/4565-3d7e3fdeb43686a8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4706.97e734bd4c9816ca.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4795-f372490b178583fc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4982.6e44352f751b9a1b.js +0 -77
- package/apps/pwa/out/_next/static/chunks/5342.49c5c5a530e62b50.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5360-08a80abdf3a4da99.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5431.66c58ab1327ee0b7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5633-d6852385000738ef.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5717.bcfcb96e701b82e0.js +0 -90
- package/apps/pwa/out/_next/static/chunks/5755-30d102586789bf7f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5957.3f1a4012388dd962.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5977-5b9e8a45a5b0c823.js +0 -1
- package/apps/pwa/out/_next/static/chunks/602.9bf02ac8e9502598.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6020.3a1b347e2d2dfacc.js +0 -8
- package/apps/pwa/out/_next/static/chunks/6375.fce1d174ba6d0324.js +0 -64
- package/apps/pwa/out/_next/static/chunks/6546.92a828aef441271f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/658.957fdb0a8c6c6c8e.js +0 -287
- package/apps/pwa/out/_next/static/chunks/6706.323590aabb8b1293.js +0 -226
- package/apps/pwa/out/_next/static/chunks/6747.b67947f293a4c02d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6868.000b24a3045c5574.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6877-74399f69c7da1433.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6946.bba74e9c96050f30.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7033.a558f1b2f6912a53.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7065.46029c26c53eac50.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7087.6fae577d09249bc1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/722.de8d9801e0f6d414.js +0 -41
- package/apps/pwa/out/_next/static/chunks/726.83532d69452ee24b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7497.57981e9d7a75a52a.js +0 -24
- package/apps/pwa/out/_next/static/chunks/7672.4af122ad892117c7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/771.6ab889a233e7dae7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7797-df5aa0381fdc078f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8060-cc008cc6fedfa818.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8085-d065d0393c1760f5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8096.f7da0776cfde6300.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8401-35e94e9091f5eb8d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8695-846034ce44852c70.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8769.815ca69879f608b4.js +0 -104
- package/apps/pwa/out/_next/static/chunks/8857-aa1cc4ac90af4d40.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8f835b4f.048eeb02299e3e12.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9068.5f2764fccf86c1b2.js +0 -93
- package/apps/pwa/out/_next/static/chunks/9103-60fbef33e66f0a46.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9247-55bcfbb0e8057f59.js +0 -1
- package/apps/pwa/out/_next/static/chunks/935.4ddaa99fc1d1126c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9451.ebfb0dcc9c02250f.js +0 -23
- package/apps/pwa/out/_next/static/chunks/9559.e648369b1d57cf9a.js +0 -62
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c1a96669158471ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-88459e0903da2803.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-d85c43f46f58716b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-4e645600579ae952.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-87edbfd19117823b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-7f0c2b7801ac6a54.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-bf1f030a9d1adffd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-cbaf66b1e1804adf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-9f5610caaa06178c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-ec8f3575e339de74.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-86d753e460f1a989.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-4166a7d51cf0a57d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-2a19c5cd3b562580.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-b6a09cde2e07521a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-f7eae1518ca0c353.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-456a8573ad811381.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-8462d6a543cbb2d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-2974cdfb87c0f9c9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-f927ffa25f3c86d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-abd86cd832aaa011.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-79daf68f6256adaa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-8c3f168fc3f91939.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-786fb4504d0f2fa9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-75209f14597dcb8f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-bf30affe3a85af7e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1187a44b7515434b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-3d0910185a66ed54.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-f401ee1dd5a26e25.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-5dfe7604fd842784.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-76cf838050a8d681.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-7ec8e289b4c14df6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-8c8ac17d52be2a79.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-d359ab048d63a9d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-b8b345c880bf78d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-f151cc10ad026940.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-9875f103057da433.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-9789328af9a9aa62.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-bf495a1e284f4e00.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-a263d94bca4be22a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-3962eab8ec58d16e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-9abcfac07e02a542.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-bee49f927c333abb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-bac2d56dcb02d955.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-937cbcc13176295c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-d09495594f7f480d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-69cb93d1a2e57e0e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-72ec543928d67c3e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-82906eeda0186a7b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/f6231284-45726550aba08fca.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-f2b4016b9b981bc8.js +0 -1
- package/apps/pwa/out/_next/static/css/f2bd5257e6af88d8.css +0 -1
- /package/apps/pwa/out/_next/static/{aBi6EyMtLsrl7J8eH4kF7 → Q-7iofoxOEv1WX18S35of}/_ssgManifest.js +0 -0
package/src/llm.ts
CHANGED
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
import { createHash } from 'node:crypto';
|
|
6
6
|
import type { LLMUsage } from './prompt-cache/types.js';
|
|
7
|
+
import { applyOpenRouterCacheControl, openRouterPromptCacheFamily } from './prompt-cache/openrouter.js';
|
|
8
|
+
import { detectLocale, type Locale } from './expression/locale.js';
|
|
9
|
+
import { format, getMessages } from './expression/i18n/index.js';
|
|
7
10
|
import type { ModelRole } from './user-config.js';
|
|
8
11
|
// ⭐ grok 자격 해석 — 구독(OAuth) 1순위 · API 키 2순위. ACP 경로와 «같은» 규칙.
|
|
9
12
|
import { isGrokUnauthorized, refreshGrokSubscriptionToken, resolveFreshGrokCredential, resolveGrokCredential } from './grok/credential.js';
|
|
@@ -16,8 +19,9 @@ import {
|
|
|
16
19
|
getGeminiApiKey, GEMINI_MODEL,
|
|
17
20
|
DEFAULT_PROVIDER,
|
|
18
21
|
} from './config.js';
|
|
19
|
-
import { debug, redactSecrets } from './debug/log.js';
|
|
22
|
+
import { debug, redactSecrets, redactSecretText } from './debug/log.js';
|
|
20
23
|
import { llmUsageCostFields } from './budget/llm-cost.js';
|
|
24
|
+
import { accumulateByokUsage } from './llm/openrouter-byok-cost.js';
|
|
21
25
|
import { ToolCallTiming } from './chat/tool-call-timing.js';
|
|
22
26
|
import {
|
|
23
27
|
dispatchWithParallelSafety,
|
|
@@ -37,8 +41,11 @@ import {
|
|
|
37
41
|
type ProviderFallbackTerminalVerdict,
|
|
38
42
|
} from './session-runtime/retry-policy.js';
|
|
39
43
|
import { fetchApiWithRetry, OverloadFailoverError, type FetchApiWithRetryOpts } from './session-runtime/retry-api.js';
|
|
44
|
+
import { BedrockProvider, isBedrockCompatibleModel, makeBedrockProvider } from './llm/bedrock-provider.js';
|
|
45
|
+
import { makeZaiCodingPlanProvider, zaiCodingPlanAvailable } from './llm/zai-coding-plan.js';
|
|
46
|
+
import { isOpenRouterDeepSeekWireModel, nonEmptyReasoningDetails, openRouterDeepSeekCatalogEffort, openRouterDeepSeekEffort, openRouterDeepSeekRequestExtras, openRouterNeedsKimiToolSchema } from './llm/openrouter-deepseek.js';
|
|
40
47
|
import { resolveModelAlias } from './intelligence-map/model-alias.js';
|
|
41
|
-
import { reasoningEffortCeiling as reasoningEffortCeilingOf } from './intelligence-map/model-catalog.js';
|
|
48
|
+
import { BUILTIN_CATALOG, reasoningEffortCeiling as reasoningEffortCeilingOf } from './intelligence-map/model-catalog.js';
|
|
42
49
|
import { inferProviderFromModel as registryInferProviderFromModel } from './registry/normalize.js';
|
|
43
50
|
import { closestMatches } from './tool-name-suggest.js';
|
|
44
51
|
import { undoTurnRuntime } from './tool-runtime/undo-turn-runtime.js';
|
|
@@ -86,9 +93,12 @@ export type ToolResultContentItem =
|
|
|
86
93
|
* - `reasoningDetails`: OpenRouter `reasoning_details[]` — 2026-09-23 · Kimi K3·GLM 은 도구 루프에서 이전 추론을
|
|
87
94
|
* 되돌려 받아야 한다(Kimi 공식 문서: 「K3 는 다중 턴·도구 호출 루프에서 필수」 · OpenRouter 가 이 배열로 통일). */
|
|
88
95
|
export interface ProviderToolMeta { thoughtSignature?: string; reasoningDetails?: Array<Record<string, unknown>> }
|
|
96
|
+
/** OR-TOOLARGS-REPAIR — 깨진 도구 인자의 요약(원문은 싣지 않는다 · 길이와 끝난 이유만). */
|
|
97
|
+
export interface ToolArgsInvalid { chars: number; finishReason: string | null }
|
|
89
98
|
|
|
90
99
|
export type ContentBlock =
|
|
91
|
-
|
|
100
|
+
/** `providerMeta` — OR-DEEPSEEK-TUNE: OpenRouter deepseek/* 의 «도구 없는» assistant 턴 추론(reasoning_details) 운반. 다른 경로는 안 싣는다. */
|
|
101
|
+
| { type: 'text'; text: string; providerMeta?: ProviderToolMeta }
|
|
92
102
|
| { type: 'image'; mediaType: string; base64: string }
|
|
93
103
|
| { type: 'audio'; mediaType: string; base64: string }
|
|
94
104
|
| { type: 'video'; mediaType: string; base64: string }
|
|
@@ -274,6 +284,10 @@ export type LLMStreamEvent =
|
|
|
274
284
|
* ("Function call is missing a thought_signature"). Other
|
|
275
285
|
* providers ignore this field. */
|
|
276
286
|
providerMeta?: ProviderToolMeta;
|
|
287
|
+
/** OR-TOOLARGS-REPAIR (2026-10-10) — 인자 JSON 이 깨져(잘림·문법 오류) 파싱에 실패했다는 표지.
|
|
288
|
+
* ⛔ OpenRouter 경로(`parseOpenAISSELines` 의 `flagInvalidToolArgs`)에서만 실린다 — 다른 공급자는 종전대로
|
|
289
|
+
* `{}` 로 대체되고 이 칸이 없다. 실리면 `args` 는 `{}` 이고, 도구 루프는 실행하지 않고 오류 결과를 돌려준다. */
|
|
290
|
+
argsInvalid?: ToolArgsInvalid;
|
|
277
291
|
}
|
|
278
292
|
/** Reasoning-summary delta from Codex Responses API (gpt-5 family).
|
|
279
293
|
* `summary_part_added` is a separator marking the boundary between
|
|
@@ -308,7 +322,9 @@ export type LLMStreamEvent =
|
|
|
308
322
|
source?: string;
|
|
309
323
|
revisedPrompt?: string;
|
|
310
324
|
}
|
|
311
|
-
| { type: 'usage'; usage: import('./prompt-cache/types.js').LLMUsage }
|
|
325
|
+
| { type: 'usage'; usage: import('./prompt-cache/types.js').LLMUsage }
|
|
326
|
+
/** OR-DEEPSEEK-TUNE — 도구 호출이 없는 턴의 OpenRouter `reasoning_details`(스트림 끝에 한 번). deepseek/* 에서만 나온다. */
|
|
327
|
+
| { type: 'reasoning_details'; details: Array<Record<string, unknown>> };
|
|
312
328
|
|
|
313
329
|
/** Tool-calling forcing (opencode parity · 2026-07-09). `'auto'` (default) lets
|
|
314
330
|
* the model decide; `'required'` forces at least one tool call; `'none'` blocks
|
|
@@ -322,10 +338,14 @@ export interface LLMOpts {
|
|
|
322
338
|
temperature?: number;
|
|
323
339
|
maxTokens?: number;
|
|
324
340
|
signal?: AbortSignal;
|
|
341
|
+
/** Override the text-stream idle watchdog per request (milliseconds). */
|
|
342
|
+
streamIdleTimeoutMs?: number;
|
|
325
343
|
/** Optional per-request usage telemetry from the provider stream. */
|
|
326
344
|
onUsage?(usage: LLMUsage): void;
|
|
327
345
|
/** Optional model role attached to this request's usage observation. */
|
|
328
346
|
usageRole?: ModelRole;
|
|
347
|
+
/** Optional streamLLM usage-ledger site override (defaults to "stream-llm"). */
|
|
348
|
+
usageSite?: string;
|
|
329
349
|
/**
|
|
330
350
|
* ⭐⭐⭐ `B3`(2026-08-19 · 대표 지시 ②) — ***턴 «안»으로 들어오는 사용자 발화의 배수구.***
|
|
331
351
|
*
|
|
@@ -370,7 +390,9 @@ export interface LLMOpts {
|
|
|
370
390
|
/** Prompt-caching toggle. Honored by Anthropic (attaches
|
|
371
391
|
* cache_control markers on system + tools + 2nd-to-last history
|
|
372
392
|
* message) and OpenAI (passes stream_options.include_usage so
|
|
373
|
-
* the automatic cache telemetry reaches us).
|
|
393
|
+
* the automatic cache telemetry reaches us). OpenRouter `anthropic/*` ·
|
|
394
|
+
* `moonshotai/*` get part-level cache_control on system (first 2) + last 2
|
|
395
|
+
* messages (`src/prompt-cache/openrouter.ts`). Default `true`.
|
|
374
396
|
* Pass `false` for tests that pin the legacy wire shape. */
|
|
375
397
|
promptCache?: boolean;
|
|
376
398
|
/** Cache TTL tier. `'5m'` (default) is the ephemeral tier; `'1h'`
|
|
@@ -459,6 +481,8 @@ export interface ToOpenAIMessagesOpts {
|
|
|
459
481
|
acceptUserMessageImages?: boolean;
|
|
460
482
|
/** OpenRouter 전용 — 도구 호출이 든 어시스턴트 메시지에 `reasoning_details` 를 되돌린다. 다른 제공자엔 안 싣는다(모르는 칸 400 방지). */
|
|
461
483
|
echoReasoningDetails?: boolean;
|
|
484
|
+
/** OR-DEEPSEEK-TUNE — deepseek/* 만: 도구 없는 assistant 턴에도 되돌리고, 빈 조각은 걷는다(`src/llm/openrouter-deepseek.ts`). */
|
|
485
|
+
deepSeekReplay?: boolean;
|
|
462
486
|
}
|
|
463
487
|
|
|
464
488
|
/**
|
|
@@ -547,9 +571,10 @@ function toOpenAIMessages(
|
|
|
547
571
|
.filter((b): b is Extract<ContentBlock, { type: 'text' }> => b.type === 'text')
|
|
548
572
|
.map(b => b.text)
|
|
549
573
|
.join('');
|
|
550
|
-
const
|
|
574
|
+
const foundDetails = opts.echoReasoningDetails
|
|
551
575
|
? toolUses.find((t) => t.providerMeta?.reasoningDetails?.length)?.providerMeta?.reasoningDetails
|
|
552
576
|
: undefined;
|
|
577
|
+
const reasoningDetails = opts.deepSeekReplay ? nonEmptyReasoningDetails(foundDetails) : foundDetails;
|
|
553
578
|
return [{
|
|
554
579
|
role: m.role,
|
|
555
580
|
content: textContent || null,
|
|
@@ -575,8 +600,12 @@ function toOpenAIMessages(
|
|
|
575
600
|
// Composer Q3=B is the primary handler; this is the wire-side
|
|
576
601
|
// defensive fallback for non-vision OpenAI / Grok / local routes.
|
|
577
602
|
const acceptUserImages = opts.acceptUserMessageImages ?? true;
|
|
603
|
+
const textTurnDetails = opts.deepSeekReplay && m.role === 'assistant'
|
|
604
|
+
? nonEmptyReasoningDetails(blocks.find((b): b is Extract<ContentBlock, { type: 'text' }> => b.type === 'text' && !!b.providerMeta?.reasoningDetails?.length)?.providerMeta?.reasoningDetails)
|
|
605
|
+
: undefined;
|
|
578
606
|
return [{
|
|
579
607
|
role: m.role,
|
|
608
|
+
...(textTurnDetails ? { reasoning_details: textTurnDetails } : {}),
|
|
580
609
|
content: blocks.map(block => {
|
|
581
610
|
if (block.type === 'text') return { type: 'text', text: block.text };
|
|
582
611
|
if (block.type === 'image') {
|
|
@@ -1109,7 +1138,12 @@ function parseHarmonyHeader(header: string): { channel: HarmonyChannel; toolName
|
|
|
1109
1138
|
* unit tests — no fetch dependency. */
|
|
1110
1139
|
export async function* parseOpenAISSELines(
|
|
1111
1140
|
lines: AsyncIterable<string> | Iterable<string>,
|
|
1141
|
+
/** OR-TOOLARGS-REPAIR (2026-10-10) — `flagInvalidToolArgs` 가 참이면(OpenRouter 경로) 인자 JSON 파싱 실패를
|
|
1142
|
+
* `{}` 로 «조용히» 바꾸지 않고 `argsInvalid` 표지를 단다(도구 루프가 실행을 막는다) ⊕ 관측을 남긴다.
|
|
1143
|
+
* ⛔ 생략·거짓이면 종전과 바이트 동일(다른 공급자 무변경). */
|
|
1144
|
+
parseOpts: { flagInvalidToolArgs?: boolean; emitTrailingReasoningDetails?: boolean } = {},
|
|
1112
1145
|
): AsyncGenerator<LLMStreamEvent, void, unknown> {
|
|
1146
|
+
const flagInvalidToolArgs = parseOpts.flagInvalidToolArgs === true;
|
|
1113
1147
|
const { parseOpenAIUsage } = await import('./prompt-cache/openai.js');
|
|
1114
1148
|
// Indexed by `tc.index` (OpenAI standard) — partial-chunk streaming
|
|
1115
1149
|
// assembles into a single accumulator per index. Gemini OpenAI-compat
|
|
@@ -1126,10 +1160,25 @@ export async function* parseOpenAISSELines(
|
|
|
1126
1160
|
reasoningDetailsAttached = true;
|
|
1127
1161
|
return [...reasoningDetailsAcc.values()];
|
|
1128
1162
|
};
|
|
1129
|
-
const yieldAccum = (acc: OpenAIToolCallAccum): LLMStreamEvent | null => {
|
|
1163
|
+
const yieldAccum = (acc: OpenAIToolCallAccum, finishReason: string | null): LLMStreamEvent | null => {
|
|
1130
1164
|
if (!acc.name) return null;
|
|
1131
1165
|
let args: Record<string, unknown> = {};
|
|
1132
|
-
|
|
1166
|
+
let argsInvalid: ToolArgsInvalid | undefined;
|
|
1167
|
+
try {
|
|
1168
|
+
args = acc.argsJson ? JSON.parse(acc.argsJson) : {};
|
|
1169
|
+
} catch {
|
|
1170
|
+
// 종전: `{}` 로 대체해 도구가 엉뚱한 기본값으로 돌았다(조용한 실패). OpenRouter 경로만 표지를 단다.
|
|
1171
|
+
if (flagInvalidToolArgs) {
|
|
1172
|
+
argsInvalid = { chars: acc.argsJson.length, finishReason };
|
|
1173
|
+
debug.log('llm.openrouter', 'tool-args-invalid', {
|
|
1174
|
+
tool: acc.name,
|
|
1175
|
+
chars: acc.argsJson.length,
|
|
1176
|
+
finishReason,
|
|
1177
|
+
// 원문은 앞 몇십 자만 · 비밀 가림.
|
|
1178
|
+
head: redactSecretText(acc.argsJson.slice(0, 60)),
|
|
1179
|
+
}, { level: 'warn' });
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1133
1182
|
const reasoningDetails = takeReasoningDetails();
|
|
1134
1183
|
const meta: ProviderToolMeta = {
|
|
1135
1184
|
...(acc.thoughtSignature !== undefined ? { thoughtSignature: acc.thoughtSignature } : {}),
|
|
@@ -1141,6 +1190,7 @@ export async function* parseOpenAISSELines(
|
|
|
1141
1190
|
name: acc.name,
|
|
1142
1191
|
args,
|
|
1143
1192
|
...(Object.keys(meta).length > 0 ? { providerMeta: meta } : {}),
|
|
1193
|
+
...(argsInvalid !== undefined ? { argsInvalid } : {}),
|
|
1144
1194
|
};
|
|
1145
1195
|
};
|
|
1146
1196
|
// Per-stream Harmony filter — routes `<|channel|>final` content to
|
|
@@ -1242,7 +1292,7 @@ export async function* parseOpenAISSELines(
|
|
|
1242
1292
|
// (or omit id on continuation frags), so this only triggers on
|
|
1243
1293
|
// the Gemini complete-frag pattern.
|
|
1244
1294
|
if (accum && tc.id && accum.id && tc.id !== accum.id && accum.argsJson.length > 0) {
|
|
1245
|
-
const ev = yieldAccum(accum);
|
|
1295
|
+
const ev = yieldAccum(accum, null);
|
|
1246
1296
|
if (ev) yield ev;
|
|
1247
1297
|
accum = undefined;
|
|
1248
1298
|
toolCalls.delete(idx);
|
|
@@ -1293,8 +1343,17 @@ export async function* parseOpenAISSELines(
|
|
|
1293
1343
|
(choice.finish_reason === 'tool_calls'
|
|
1294
1344
|
|| (choice.finish_reason && toolCalls.size > 0))
|
|
1295
1345
|
) {
|
|
1346
|
+
// OR-TOOLARGS-REPAIR — 출력 상한에서 잘린 턴(`length`)의 도구 호출은 인자가 온전해 보여도 «잘렸을 수 있다».
|
|
1347
|
+
// 관측만 남긴다(파싱 실패면 yieldAccum 이 `argsInvalid` 로 막는다). 상한 조정은 범위 밖.
|
|
1348
|
+
if (flagInvalidToolArgs && choice.finish_reason === 'length' && toolCalls.size > 0) {
|
|
1349
|
+
debug.log('llm.openrouter', 'tool-args-maybe-truncated', {
|
|
1350
|
+
finishReason: 'length',
|
|
1351
|
+
tools: [...toolCalls.values()].map((tc) => tc.name),
|
|
1352
|
+
chars: [...toolCalls.values()].map((tc) => tc.argsJson.length),
|
|
1353
|
+
}, { level: 'warn' });
|
|
1354
|
+
}
|
|
1296
1355
|
for (const [, tc] of toolCalls) {
|
|
1297
|
-
const ev = yieldAccum(tc);
|
|
1356
|
+
const ev = yieldAccum(tc, typeof choice.finish_reason === 'string' ? choice.finish_reason : null);
|
|
1298
1357
|
if (ev) yield ev;
|
|
1299
1358
|
}
|
|
1300
1359
|
toolCalls.clear();
|
|
@@ -1308,6 +1367,11 @@ export async function* parseOpenAISSELines(
|
|
|
1308
1367
|
yield { type: 'reasoning', kind: 'inline_delta', delta: tail.reasoningDelta };
|
|
1309
1368
|
}
|
|
1310
1369
|
yield* emitHarmonyTools(tail.toolCalls);
|
|
1370
|
+
// OR-DEEPSEEK-TUNE — 도구 호출에 실리지 못한 추론(텍스트만 낸 턴)을 끝에 한 번 낸다. deepseek/* 만 켠다.
|
|
1371
|
+
if (parseOpts.emitTrailingReasoningDetails) {
|
|
1372
|
+
const details = takeReasoningDetails();
|
|
1373
|
+
if (details) yield { type: 'reasoning_details', details };
|
|
1374
|
+
}
|
|
1311
1375
|
}
|
|
1312
1376
|
|
|
1313
1377
|
/** Pick a stable provider name for `fetchApiWithRetry` telemetry from
|
|
@@ -1329,6 +1393,7 @@ function retryOptsFor(
|
|
|
1329
1393
|
}
|
|
1330
1394
|
|
|
1331
1395
|
function inferOpenAIProviderName(url: string): string {
|
|
1396
|
+
if (/^https?:\/\/openrouter\.ai(?::\d+)?(?:\/|$)/i.test(url)) return 'openrouter';
|
|
1332
1397
|
if (url.includes('x.ai')) return 'grok';
|
|
1333
1398
|
if (url.includes('openai.com')) return 'openai';
|
|
1334
1399
|
if (url.includes('localhost') || url.includes('127.0.0.1')) return 'local';
|
|
@@ -1383,7 +1448,10 @@ async function* streamOpenAIEvents(
|
|
|
1383
1448
|
let textChars = 0;
|
|
1384
1449
|
let toolCalls = 0;
|
|
1385
1450
|
try {
|
|
1386
|
-
|
|
1451
|
+
// OR-TOOLARGS-REPAIR — 깨진 도구 인자 표지는 OpenRouter 엔드포인트에서만 켠다(다른 공급자 무변경).
|
|
1452
|
+
const flagInvalidToolArgs = inferOpenAIProviderName(url) === 'openrouter';
|
|
1453
|
+
const emitTrailingReasoningDetails = flagInvalidToolArgs && typeof body?.model === 'string' && isOpenRouterDeepSeekWireModel(body.model);
|
|
1454
|
+
for await (const ev of parseOpenAISSELines(sseLineStream(response.body!), flagInvalidToolArgs ? { flagInvalidToolArgs, ...(emitTrailingReasoningDetails ? { emitTrailingReasoningDetails } : {}) } : {})) {
|
|
1387
1455
|
if (ev.type === 'text') textChars += ev.delta.length;
|
|
1388
1456
|
else if (ev.type === 'tool_call') toolCalls++;
|
|
1389
1457
|
yield ev;
|
|
@@ -2420,12 +2488,29 @@ export function dedupeToolsByName(tools: LLMToolSpec[] | undefined): LLMToolSpec
|
|
|
2420
2488
|
return out.length === tools.length ? tools : out;
|
|
2421
2489
|
}
|
|
2422
2490
|
|
|
2423
|
-
|
|
2491
|
+
/** OpenRouter's Moonshot/Kimi tool schema accepts a bare $ref and single-schema items. */
|
|
2492
|
+
export function sanitizeToolSchemaForKimi(schema: unknown): unknown {
|
|
2493
|
+
if (Array.isArray(schema)) return schema.map(sanitizeToolSchemaForKimi);
|
|
2494
|
+
if (!schema || typeof schema !== 'object') return schema;
|
|
2495
|
+
const record = schema as Record<string, unknown>;
|
|
2496
|
+
if ('$ref' in record) return { $ref: record.$ref };
|
|
2497
|
+
return Object.fromEntries(Object.entries(record).map(([key, value]) => [
|
|
2498
|
+
key,
|
|
2499
|
+
sanitizeToolSchemaForKimi(key === 'items' && Array.isArray(value) ? value[0] : value),
|
|
2500
|
+
]));
|
|
2501
|
+
}
|
|
2502
|
+
|
|
2503
|
+
export function toOpenAITools(tools: LLMToolSpec[] | undefined, kimi = false): any[] | undefined {
|
|
2424
2504
|
const unique = dedupeToolsByName(tools);
|
|
2425
2505
|
if (!unique || unique.length === 0) return undefined;
|
|
2426
2506
|
return unique.map(t => ({
|
|
2427
2507
|
type: 'function',
|
|
2428
|
-
function: {
|
|
2508
|
+
function: {
|
|
2509
|
+
name: t.name, description: t.description,
|
|
2510
|
+
parameters: kimi
|
|
2511
|
+
? sanitizeToolSchemaForKimi(strictifyToolSchema(t.parameters))
|
|
2512
|
+
: strictifyToolSchema(t.parameters),
|
|
2513
|
+
},
|
|
2429
2514
|
}));
|
|
2430
2515
|
}
|
|
2431
2516
|
|
|
@@ -3904,6 +3989,7 @@ export const PROVIDERS: Record<string, LLMProvider> = {
|
|
|
3904
3989
|
streamChat: (messages, opts = {}) => makeOpenRouterProvider({ provider: 'openrouter' }).streamChat!(messages, opts),
|
|
3905
3990
|
chat: (messages, opts = {}) => makeOpenRouterProvider({ provider: 'openrouter' }).chat!(messages, opts),
|
|
3906
3991
|
},
|
|
3992
|
+
bedrock: BedrockProvider, // 명시 선택 전용 — 자동 순서·폴백 체인에 «안» 넣는다(src/llm/bedrock-provider.ts)
|
|
3907
3993
|
};
|
|
3908
3994
|
|
|
3909
3995
|
const AUTOMATIC_PROVIDER_ORDER = ['grok', 'anthropic', 'gemini', 'local'] as const;
|
|
@@ -4085,12 +4171,13 @@ export function decideProviderForConfig(
|
|
|
4085
4171
|
return { provider, model: selectedModel, auth: baseUrl || getLocalLLMUrl() ? 'local' : 'none' };
|
|
4086
4172
|
case 'openrouter':
|
|
4087
4173
|
return { provider, model: selectedModel, auth: apiKey || getOpenRouterApiKey() ? 'apikey' : 'none' };
|
|
4174
|
+
case 'bedrock': return { provider, model: selectedModel, auth: authKindForProvider('bedrock', selectedModel) };
|
|
4088
4175
|
}
|
|
4089
4176
|
throw new Error(`unknown provider: ${provider as string}`);
|
|
4090
4177
|
}
|
|
4091
4178
|
|
|
4092
4179
|
function isKnownProviderName(provider: string): provider is ConcreteProviderName {
|
|
4093
|
-
return provider === 'grok' || provider === 'openai' || provider === 'openai-codex' || provider === 'anthropic' || provider === 'gemini' || provider === 'local' || provider === 'openrouter';
|
|
4180
|
+
return provider === 'grok' || provider === 'openai' || provider === 'openai-codex' || provider === 'anthropic' || provider === 'gemini' || provider === 'local' || provider === 'openrouter' || provider === 'bedrock';
|
|
4094
4181
|
}
|
|
4095
4182
|
|
|
4096
4183
|
function authKindForProvider(provider: string, model: string, apiKey?: string): ProviderDecisionAuth {
|
|
@@ -4105,6 +4192,7 @@ function authKindForProvider(provider: string, model: string, apiKey?: string):
|
|
|
4105
4192
|
if (provider === 'anthropic') return getAnthropicApiKey() ? 'apikey' : 'none';
|
|
4106
4193
|
if (provider === 'gemini') return getGeminiApiKey() ? 'apikey' : 'none';
|
|
4107
4194
|
if (provider === 'openrouter') return getOpenRouterApiKey() ? 'apikey' : 'none';
|
|
4195
|
+
if (provider === 'bedrock') return BedrockProvider.available() ? 'apikey' : 'none';
|
|
4108
4196
|
if (provider === 'openai-codex') {
|
|
4109
4197
|
try {
|
|
4110
4198
|
return codexOAuthAvailable() ? 'oauth' : 'none';
|
|
@@ -4124,6 +4212,7 @@ function defaultModelForProvider(provider: ConcreteProviderName): string {
|
|
|
4124
4212
|
case 'gemini': return GEMINI_MODEL;
|
|
4125
4213
|
case 'local': return LOCAL_LLM_MODEL;
|
|
4126
4214
|
case 'openrouter': return OPENROUTER_MODEL;
|
|
4215
|
+
case 'bedrock': return BedrockProvider.defaultModel;
|
|
4127
4216
|
}
|
|
4128
4217
|
throw new Error(`unknown provider: ${provider as string}`);
|
|
4129
4218
|
}
|
|
@@ -4226,6 +4315,26 @@ function finalizeStreamingProviderModel(provider: LLMProvider, model: string): {
|
|
|
4226
4315
|
return { provider: finalizedProvider, model: finalized.model };
|
|
4227
4316
|
}
|
|
4228
4317
|
|
|
4318
|
+
/** ZAI-POD-CHILD(10-11 실측 · si-task-aaf5d691e4ed) — 레지스트리는 `glm-` 접두를 local 로 본다.
|
|
4319
|
+
* 활성 provider 가 `glm`(`ELANOUS_LLM_PROVIDER=glm` 포함)일 때 모델 이름으로 provider 를 고르는 길
|
|
4320
|
+
* (gate 진단·리뷰 `getProvider(model)`)이 local 로 떨어져 «Local LLM unavailable» 로 죽었다.
|
|
4321
|
+
* ⇒ 그때만 설정 경로(`getProviderForConfig`)를 탄다 — 키가 있으면 Z.ai 공급자, 없으면 OpenRouter 안내 오류.
|
|
4322
|
+
* 활성 provider 가 glm 이 아니면 undefined(종전 그대로). */
|
|
4323
|
+
function activeGlmProviderForModel(model: string): LLMProvider | undefined {
|
|
4324
|
+
if (!model.trim().toLowerCase().startsWith('glm-')) return undefined;
|
|
4325
|
+
let cfg: UserConfig;
|
|
4326
|
+
try {
|
|
4327
|
+
const { getUserConfig } = require('./user-config.js') as typeof import('./user-config.js');
|
|
4328
|
+
cfg = getUserConfig();
|
|
4329
|
+
} catch (e) {
|
|
4330
|
+
debug.log('llm.router', 'getProvider.glm-config-unreadable', { requestedModel: model, error: e instanceof Error ? e.message : String(e) }, { level: 'warn' });
|
|
4331
|
+
return undefined;
|
|
4332
|
+
}
|
|
4333
|
+
if (cfg.llm.provider !== 'glm') return undefined;
|
|
4334
|
+
debug.log('llm.router', 'getProvider.glm-active', { requestedModel: model }, { level: 'info' });
|
|
4335
|
+
return getProviderForConfig(cfg, model);
|
|
4336
|
+
}
|
|
4337
|
+
|
|
4229
4338
|
/**
|
|
4230
4339
|
* Pick a provider based on the model name. If model is undefined, use first
|
|
4231
4340
|
* available provider (preferring DEFAULT_PROVIDER env var if set).
|
|
@@ -4237,6 +4346,8 @@ export function getProvider(model?: string): LLMProvider {
|
|
|
4237
4346
|
// ids (e.g. `claude-opus-4-7`) so prefix matching works. Existing
|
|
4238
4347
|
// full ids pass through unchanged.
|
|
4239
4348
|
const resolved = resolveModelAlias(model) ?? model;
|
|
4349
|
+
const glmDirect = activeGlmProviderForModel(resolved);
|
|
4350
|
+
if (glmDirect) return glmDirect;
|
|
4240
4351
|
// Preserve the historical Chat Completions route for gpt-* model-only
|
|
4241
4352
|
// requests, including future ids that the current catalog does not list.
|
|
4242
4353
|
if (resolved.toLowerCase().startsWith('gpt-')) return PROVIDERS.openai!;
|
|
@@ -4247,7 +4358,7 @@ export function getProvider(model?: string): LLMProvider {
|
|
|
4247
4358
|
if (adapted && PROVIDERS[adapted]) return PROVIDERS[adapted]!;
|
|
4248
4359
|
// Unknown prefix — look up by exact name match on defaults
|
|
4249
4360
|
for (const p of Object.values(PROVIDERS)) {
|
|
4250
|
-
if (p.defaultModel === resolved) return p;
|
|
4361
|
+
if (p.name !== 'bedrock' && p.defaultModel === resolved) return p; // bedrock 은 명시 선택 전용
|
|
4251
4362
|
}
|
|
4252
4363
|
}
|
|
4253
4364
|
|
|
@@ -4374,6 +4485,8 @@ export function buildMessagesWithContext(
|
|
|
4374
4485
|
|
|
4375
4486
|
// Re-export converters so tests/adapters can assert wire-format correctness.
|
|
4376
4487
|
export { toOpenAIMessage, toOpenAIMessages, toAnthropicMessage, systemToAnthropicString };
|
|
4488
|
+
export { usesAdaptiveThinking, mapReasoningLevelToAnthropicThinking, mapReasoningLevelToAnthropicEffort, sseLineStream, retryOptsFor }; // src/llm/bedrock-provider.ts
|
|
4489
|
+
export { makeOpenAICompatProvider, makeOpenRouterProvider }; // src/llm/zai-coding-plan.ts
|
|
4377
4490
|
|
|
4378
4491
|
/**
|
|
4379
4492
|
* Best-effort classification of whether a model accepts image inputs.
|
|
@@ -4430,7 +4543,10 @@ export function isLikelyVisionModel(model: string | undefined): boolean {
|
|
|
4430
4543
|
* Convenience wrapper — stream chunks via a callback, returning the full text.
|
|
4431
4544
|
* Mirrors the existing `streamGrok()` signature in chat.ts for drop-in use.
|
|
4432
4545
|
*/
|
|
4433
|
-
|
|
4546
|
+
// ⭐ OPENROUTER-OPTIMIZE G9 — `reportedCostUsd`(OpenRouter `usage.cost`)도 싣는다. 빠지면 `stream-llm` 행이
|
|
4547
|
+
// 실청구액을 잃고 카탈로그 추정(대개 `cost.kind=unknown`)으로 떨어진다(리뷰·저작 행 실측).
|
|
4548
|
+
// 합산은 토큰 칸과 같은 규약이다 — OpenAI 호환 스트림은 `usage` 를 마지막 청크에 «한 번» 싣는다(누적 반복 보고 아님).
|
|
4549
|
+
type ObservedUsage = Pick<LLMUsage, 'inputTokens' | 'outputTokens' | 'cacheReadInputTokens' | 'cacheCreationInputTokens' | 'reportedCostUsd' | 'byok' | 'upstreamCostUsd'>;
|
|
4434
4550
|
|
|
4435
4551
|
type ProviderTextResult =
|
|
4436
4552
|
| { ok: true; full: string; usage: ObservedUsage | 'unmeasured' }
|
|
@@ -4438,10 +4554,10 @@ type ProviderTextResult =
|
|
|
4438
4554
|
|
|
4439
4555
|
function accumulateUsage(usage: ObservedUsage | undefined, received: LLMUsage): ObservedUsage {
|
|
4440
4556
|
const total = { ...usage };
|
|
4441
|
-
for (const field of ['inputTokens', 'outputTokens', 'cacheReadInputTokens', 'cacheCreationInputTokens'] as const) {
|
|
4557
|
+
for (const field of ['inputTokens', 'outputTokens', 'cacheReadInputTokens', 'cacheCreationInputTokens', 'reportedCostUsd'] as const) {
|
|
4442
4558
|
if (received[field] !== undefined) total[field] = (total[field] ?? 0) + received[field];
|
|
4443
4559
|
}
|
|
4444
|
-
return total;
|
|
4560
|
+
return accumulateByokUsage(total, received); // OR-BYOK-COST
|
|
4445
4561
|
}
|
|
4446
4562
|
|
|
4447
4563
|
async function consumeProviderText(
|
|
@@ -4468,17 +4584,40 @@ async function consumeProviderText(
|
|
|
4468
4584
|
// Preserve the provider or callback error that caused this close.
|
|
4469
4585
|
}
|
|
4470
4586
|
};
|
|
4587
|
+
const idleMs = opts.streamIdleTimeoutMs ?? (
|
|
4588
|
+
usesLongReasoningIdle(getModelFamily(opts.model ?? provider.defaultModel), provider.name)
|
|
4589
|
+
? STREAM_IDLE_TIMEOUT_MS_REASONING : STREAM_IDLE_TIMEOUT_MS
|
|
4590
|
+
);
|
|
4471
4591
|
|
|
4472
4592
|
while (true) {
|
|
4473
|
-
let
|
|
4593
|
+
let idleTimer: ReturnType<typeof setTimeout> | undefined;
|
|
4594
|
+
let step: { idle: true } | { idle: false; result: IteratorResult<string | LLMStreamEvent> };
|
|
4474
4595
|
try {
|
|
4475
|
-
step = await
|
|
4596
|
+
step = await Promise.race([
|
|
4597
|
+
iterator.next().then((result) => ({ idle: false as const, result })),
|
|
4598
|
+
new Promise<{ idle: true }>((resolve) => {
|
|
4599
|
+
idleTimer = setTimeout(() => resolve({ idle: true }), idleMs);
|
|
4600
|
+
}),
|
|
4601
|
+
]);
|
|
4476
4602
|
} catch (error) {
|
|
4477
4603
|
await closeIterator();
|
|
4478
4604
|
return { ok: false, full, error };
|
|
4605
|
+
} finally {
|
|
4606
|
+
if (idleTimer !== undefined) clearTimeout(idleTimer);
|
|
4479
4607
|
}
|
|
4480
|
-
if (step.
|
|
4481
|
-
|
|
4608
|
+
if (step.idle) {
|
|
4609
|
+
debug.log('llm', 'stream-idle-timeout', {
|
|
4610
|
+
provider: provider.name, model: opts.model ?? provider.defaultModel,
|
|
4611
|
+
idleMs, receivedChars: full.length, site: 'stream-llm',
|
|
4612
|
+
});
|
|
4613
|
+
const error = new Error(`stream idle timeout after ${idleMs}ms`);
|
|
4614
|
+
error.name = 'StreamIdleTimeoutError';
|
|
4615
|
+
// An async generator can leave return() pending behind a stalled next().
|
|
4616
|
+
void closeIterator();
|
|
4617
|
+
return { ok: false, full, error };
|
|
4618
|
+
}
|
|
4619
|
+
if (step.result.done) return { ok: true, full, usage: usage ?? 'unmeasured' };
|
|
4620
|
+
const event = typeof step.result.value === 'string' ? { type: 'text' as const, delta: step.result.value } : step.result.value;
|
|
4482
4621
|
if (event.type === 'usage') {
|
|
4483
4622
|
usage = accumulateUsage(usage, event.usage);
|
|
4484
4623
|
try {
|
|
@@ -4504,11 +4643,11 @@ export async function streamLLM(
|
|
|
4504
4643
|
onChunk: (delta: string, full: string) => void,
|
|
4505
4644
|
opts: LLMOpts & { provider?: LLMProvider; initialProvider?: LLMProvider; onResolvedProvider?: (provider: string, model: string) => void } = {},
|
|
4506
4645
|
): Promise<string> {
|
|
4646
|
+
const started = Date.now();
|
|
4507
4647
|
let activeProvider = opts.provider ?? opts.initialProvider ?? resolveDefaultProvider(opts.model);
|
|
4508
4648
|
const attemptedProviders = new Set<string>([activeProvider.name]);
|
|
4509
4649
|
let blockedProviders: ProviderFallbackAttempt[] = [];
|
|
4510
4650
|
let modelOverride = opts.model;
|
|
4511
|
-
const started = Date.now();
|
|
4512
4651
|
|
|
4513
4652
|
while (true) {
|
|
4514
4653
|
const finalized = finalizeStreamingProviderModel(
|
|
@@ -4527,6 +4666,7 @@ export async function streamLLM(
|
|
|
4527
4666
|
maxTokens: opts.maxTokens,
|
|
4528
4667
|
temperature: opts.temperature,
|
|
4529
4668
|
}, { level: 'info' });
|
|
4669
|
+
// Keep text-only stream failures on streamLLM's existing provider fallback path.
|
|
4530
4670
|
const consumed = await consumeProviderText(
|
|
4531
4671
|
activeProvider,
|
|
4532
4672
|
messages,
|
|
@@ -4541,9 +4681,10 @@ export async function streamLLM(
|
|
|
4541
4681
|
if (consumed.ok) {
|
|
4542
4682
|
if (consumed.usage !== 'unmeasured') {
|
|
4543
4683
|
try {
|
|
4544
|
-
logAgentTurnUsage(activeModel, consumed.usage, { providerName: activeProvider.name, site: 'stream-llm', role: opts.usageRole });
|
|
4684
|
+
logAgentTurnUsage(activeModel, consumed.usage, { providerName: activeProvider.name, site: opts.usageSite ?? 'stream-llm', role: opts.usageRole });
|
|
4545
4685
|
} catch { /* best-effort observation */ }
|
|
4546
4686
|
}
|
|
4687
|
+
debug.log('llm', 'outcome', { provider: activeProvider.name, status: 'ok', kind: 'streamLLM', durationMs: Date.now() - started });
|
|
4547
4688
|
debug.log('llm.router.done', 'streamLLM', {
|
|
4548
4689
|
provider: activeProvider.name,
|
|
4549
4690
|
model: activeModel,
|
|
@@ -4579,7 +4720,10 @@ export async function streamLLM(
|
|
|
4579
4720
|
message: reason,
|
|
4580
4721
|
...(isAuthRejectionError(err) ? { authRejected: true } : {}),
|
|
4581
4722
|
}, { level: 'error' });
|
|
4582
|
-
if (opts.provider)
|
|
4723
|
+
if (opts.provider) {
|
|
4724
|
+
debug.log('llm', 'outcome', { provider: activeProvider.name, status: 'error', kind: 'streamLLM', durationMs: Date.now() - started });
|
|
4725
|
+
throw err;
|
|
4726
|
+
}
|
|
4583
4727
|
const remaining = remainingFallbackProviderNames(attemptedProviders, opts);
|
|
4584
4728
|
const verdict = decideProviderFallback({
|
|
4585
4729
|
err,
|
|
@@ -4604,6 +4748,7 @@ export async function streamLLM(
|
|
|
4604
4748
|
continue;
|
|
4605
4749
|
}
|
|
4606
4750
|
if (verdict.action === 'stop') {
|
|
4751
|
+
debug.log('llm', 'outcome', { provider: activeProvider.name, status: 'error', kind: 'streamLLM', durationMs: Date.now() - started });
|
|
4607
4752
|
debug.log('llm.router', 'provider-fallback-stop', {
|
|
4608
4753
|
blockedProviders,
|
|
4609
4754
|
category: verdict.category,
|
|
@@ -4622,6 +4767,7 @@ export async function streamLLM(
|
|
|
4622
4767
|
...(fallback ? { skippedFallbackProvider: fallback.name, emittedChars: full.length } : {}),
|
|
4623
4768
|
}, { level: 'error' });
|
|
4624
4769
|
onChunk(finalDelta, finalText);
|
|
4770
|
+
debug.log('llm', 'outcome', { provider: activeProvider.name, status: 'fallback-exhausted', kind: 'streamLLM', durationMs: Date.now() - started });
|
|
4625
4771
|
return finalText;
|
|
4626
4772
|
}
|
|
4627
4773
|
}
|
|
@@ -5019,6 +5165,15 @@ const LOCAL_TOOL_DISCIPLINE = [
|
|
|
5019
5165
|
'- 범위 읽기만으로 판단할 수 없을 때에만 전체 읽기를 선택하고, 읽은 뒤에는 다음 행동을 계속 결정하라.',
|
|
5020
5166
|
].join('\n');
|
|
5021
5167
|
|
|
5168
|
+
/** OpenRouter(`openrouter/…`) GLM·Kimi·Qwen 전용 도구 호출 규율 — 다른 군 상수와 합성하지 않는 독립 상수. */
|
|
5169
|
+
export const OPEN_WEIGHT_TOOL_DISCIPLINE = [
|
|
5170
|
+
'[open-weight tool-use discipline]',
|
|
5171
|
+
'- 도구로 할 수 있는 일은 이번 응답에서 바로 도구를 호출하라. "먼저 읽겠다" 또는 "확인하겠다" 같은 계획만 말하고 응답을 끝내지 마라.',
|
|
5172
|
+
'- 작업을 시작하는 첫 응답에는 도구 호출이 하나 이상 있어야 한다.',
|
|
5173
|
+
'- 도구 호출 인자는 해당 도구의 스키마에 맞는 JSON 으로 내라.',
|
|
5174
|
+
'- 충분한 근거가 모이면 도구 호출 없이 최종 답을 평문으로 써서 끝내라.',
|
|
5175
|
+
].join('\n');
|
|
5176
|
+
|
|
5022
5177
|
/** 모델군 → 그 군에 주입할 툴 규율(없으면 `null`). **능력 술어 판** — 2026-08-14.
|
|
5023
5178
|
*
|
|
5024
5179
|
* ⛔ **왜 `if` 세 개가 아니라 이 표인가**: codex·grok·local 이 각각 「같은 모양의 if」로 붙어 있었고,
|
|
@@ -5040,6 +5195,7 @@ const TOOL_DISCIPLINE_BY_FAMILY: Record<ModelFamily, string | null> = {
|
|
|
5040
5195
|
codex: CODEX_TOOL_DISCIPLINE,
|
|
5041
5196
|
grok: GROK_TOOL_DISCIPLINE,
|
|
5042
5197
|
local: LOCAL_TOOL_DISCIPLINE,
|
|
5198
|
+
'open-weight': OPEN_WEIGHT_TOOL_DISCIPLINE,
|
|
5043
5199
|
// ⬇ 아래 넷은 「아직 안 쟀다」이지 「필요 없다」가 아니다.
|
|
5044
5200
|
// `other` 가 0인 것은 ***아무도 other 를 안 쟀기 때문***이고, 실제 자식 하나가 오늘 `other` 였다(`[S]` 실측).
|
|
5045
5201
|
claude: null,
|
|
@@ -5217,6 +5373,19 @@ function appendFinalSynthesisNotice(existingText: string, notice: string): strin
|
|
|
5217
5373
|
return existingText.length > 0 ? `${existingText}\n\n${notice}` : notice;
|
|
5218
5374
|
}
|
|
5219
5375
|
|
|
5376
|
+
export function buildNoFinalSynthesisLead(
|
|
5377
|
+
reason: 'empty-turn' | 'budget-exhausted',
|
|
5378
|
+
toolCallCount: number,
|
|
5379
|
+
locale?: Locale,
|
|
5380
|
+
): string {
|
|
5381
|
+
if (reason === 'empty-turn') {
|
|
5382
|
+
return (locale ?? detectLocale()) === 'ko'
|
|
5383
|
+
? '답을 끝까지 쓰지 못했습니다 — 빈 응답이 이어졌습니다. 질문을 좁혀 다시 물어 주세요(예: 무엇 하나만).'
|
|
5384
|
+
: 'I could not finish the answer — repeated empty responses stopped the reply. Please ask a narrower question (for example, just one thing).';
|
|
5385
|
+
}
|
|
5386
|
+
return format(getMessages(locale).chatNoSynthesisLead ?? getMessages('en').chatNoSynthesisLead!, { n: toolCallCount });
|
|
5387
|
+
}
|
|
5388
|
+
|
|
5220
5389
|
function buildNoFinalSynthesisNotice(reason: 'empty-turn' | 'budget-exhausted'): string {
|
|
5221
5390
|
const why = reason === 'empty-turn'
|
|
5222
5391
|
? 'The model stopped after repeated empty turns.'
|
|
@@ -7744,6 +7913,7 @@ export function selectIntentClassificationMessages(messages: readonly LLMMessage
|
|
|
7744
7913
|
message.content === CODEX_TOOL_DISCIPLINE
|
|
7745
7914
|
|| message.content === GROK_TOOL_DISCIPLINE
|
|
7746
7915
|
|| message.content === LOCAL_TOOL_DISCIPLINE
|
|
7916
|
+
|| message.content === OPEN_WEIGHT_TOOL_DISCIPLINE
|
|
7747
7917
|
)
|
|
7748
7918
|
));
|
|
7749
7919
|
}
|
|
@@ -7956,12 +8126,13 @@ export async function streamLLMWithTools(
|
|
|
7956
8126
|
// the caller — no per-turn duplication when the caller persists new messages.
|
|
7957
8127
|
// Adapters fold multiple system messages, so this composes with (does not
|
|
7958
8128
|
// mutate) the caller's persona/system prompt.
|
|
7959
|
-
// ⭐
|
|
8129
|
+
// ⭐ 각 모델군의 규율은 같은 해소 지점에서 선택한다.
|
|
7960
8130
|
// 대표 2026-08-14: *"claude 제외 다른 LLM 들이 공용화가 많아 보이고, 오히려 claude 일 때
|
|
7961
8131
|
// 옵션화를 해야 하는 게 아닌지"* ⊕ `[S]` 와 합의한 축 분담(축② = 능력 술어는 `[T]` 소유).
|
|
7962
|
-
// ⛔
|
|
8132
|
+
// ⛔ 기존 군의 문면은 «바이트 하나» 안 바뀐다(테스트가 전송분으로 문다).
|
|
7963
8133
|
const toolDiscipline = resolveToolDiscipline(modelFamily);
|
|
7964
8134
|
if (toolDiscipline !== null) {
|
|
8135
|
+
debug.log('llm.tool-discipline', 'injected', { modelFamily, model: effectiveModel, chars: toolDiscipline.length });
|
|
7965
8136
|
// ⛔ **상수를 «그대로» 싣는다 — 합성하지 마라.**
|
|
7966
8137
|
// `selectIntentClassificationMessages` 가 «정확 일치»로 이 메시지를 걸러 내므로,
|
|
7967
8138
|
// 여기서 한 글자라도 덧붙이면 ***분류기 셋이 다시 «오염»된다***(그 함수 주석에 실측이 있다).
|
|
@@ -8087,11 +8258,16 @@ export async function streamLLMWithTools(
|
|
|
8087
8258
|
},
|
|
8088
8259
|
};
|
|
8089
8260
|
}
|
|
8261
|
+
// OR-DEEPSEEK-TUNE — 마지막 턴의 «도구 없는» 추론(deepseek/* 만 채워진다). 매 턴 시작에 비운다.
|
|
8262
|
+
let turnReasoningDetails: Array<Record<string, unknown>> | undefined;
|
|
8090
8263
|
const emitTurnComplete = (finalAssistantText?: string): void => {
|
|
8091
8264
|
if (finalAssistantText && finalAssistantText.length > 0) {
|
|
8092
8265
|
history.push({
|
|
8093
8266
|
role: 'assistant',
|
|
8094
|
-
content: [{
|
|
8267
|
+
content: [{
|
|
8268
|
+
type: 'text', text: finalAssistantText,
|
|
8269
|
+
...(turnReasoningDetails ? { providerMeta: { reasoningDetails: turnReasoningDetails } } : {}),
|
|
8270
|
+
}],
|
|
8095
8271
|
});
|
|
8096
8272
|
}
|
|
8097
8273
|
handlers.onTurnComplete?.(history.slice(initialHistoryLen));
|
|
@@ -8300,11 +8476,13 @@ export async function streamLLMWithTools(
|
|
|
8300
8476
|
}
|
|
8301
8477
|
}
|
|
8302
8478
|
let turnText = '';
|
|
8479
|
+
turnReasoningDetails = undefined;
|
|
8303
8480
|
const pendingCalls: Array<{
|
|
8304
8481
|
id: string;
|
|
8305
8482
|
name: string;
|
|
8306
8483
|
args: Record<string, unknown>;
|
|
8307
8484
|
providerMeta?: ProviderToolMeta;
|
|
8485
|
+
argsInvalid?: ToolArgsInvalid;
|
|
8308
8486
|
}> = [];
|
|
8309
8487
|
const turnStartedAt = Date.now();
|
|
8310
8488
|
debug.log('llm.router', 'tool-loop.turn.start', {
|
|
@@ -8514,12 +8692,15 @@ export async function streamLLMWithTools(
|
|
|
8514
8692
|
turnText += ev.delta;
|
|
8515
8693
|
fullText += ev.delta;
|
|
8516
8694
|
handlers.onText(ev.delta, fullText);
|
|
8695
|
+
} else if (ev.type === 'reasoning_details') {
|
|
8696
|
+
turnReasoningDetails = ev.details;
|
|
8517
8697
|
} else if (ev.type === 'tool_call') {
|
|
8518
8698
|
pendingCalls.push({
|
|
8519
8699
|
id: ev.id,
|
|
8520
8700
|
name: ev.name,
|
|
8521
8701
|
args: ev.args,
|
|
8522
8702
|
...(ev.providerMeta !== undefined ? { providerMeta: ev.providerMeta } : {}),
|
|
8703
|
+
...(ev.argsInvalid !== undefined ? { argsInvalid: ev.argsInvalid } : {}),
|
|
8523
8704
|
});
|
|
8524
8705
|
} else if (ev.type === 'reasoning') {
|
|
8525
8706
|
// Forward to the optional reasoning handler. Codex Responses
|
|
@@ -8660,11 +8841,12 @@ export async function streamLLMWithTools(
|
|
|
8660
8841
|
if (pendingCalls.length === 0 && turnText.length === 0) {
|
|
8661
8842
|
if (emptyRetries >= MAX_EMPTY_RETRIES) {
|
|
8662
8843
|
const notice = buildNoFinalSynthesisNotice('empty-turn');
|
|
8663
|
-
const
|
|
8844
|
+
const visibleText = finalizeVisibleAssistantText(
|
|
8664
8845
|
appendFinalSynthesisNotice(fullText, notice),
|
|
8665
8846
|
notice,
|
|
8666
8847
|
sawToolRound,
|
|
8667
8848
|
);
|
|
8849
|
+
const finalText = `${buildNoFinalSynthesisLead('empty-turn', toolCallHistory.length)}\n\n${visibleText}`;
|
|
8668
8850
|
handlers.onText('', finalText);
|
|
8669
8851
|
debug.log('llm.router', 'tool-loop.empty-turn.give-up', {
|
|
8670
8852
|
turn, emptyRetries, finalTextInjected: true,
|
|
@@ -9558,6 +9740,22 @@ export async function streamLLMWithTools(
|
|
|
9558
9740
|
return { result: stub, isError: true, phaseRejected: false };
|
|
9559
9741
|
}
|
|
9560
9742
|
}
|
|
9743
|
+
// OR-TOOLARGS-REPAIR (2026-10-10) — 인자 JSON 이 깨진 호출(OpenRouter 경로만 표지가 붙는다)은
|
|
9744
|
+
// ⛔ 실행하지 않는다. 종전엔 `{}` 로 실행돼 도구가 기본값으로 돌고 모델은 «성공»을 받았다.
|
|
9745
|
+
// 기존 dispatch 오류 결과 모양(`{ error }` ⊕ isError)으로 돌려 모델이 다시 부르게 한다.
|
|
9746
|
+
if (call.argsInvalid !== undefined) {
|
|
9747
|
+
debug.log('llm.router', 'tool-loop.tool-args-invalid.blocked', {
|
|
9748
|
+
turn,
|
|
9749
|
+
tool: call.name,
|
|
9750
|
+
chars: call.argsInvalid.chars,
|
|
9751
|
+
finishReason: call.argsInvalid.finishReason,
|
|
9752
|
+
}, { level: 'warn' });
|
|
9753
|
+
return {
|
|
9754
|
+
result: { error: buildInvalidToolArgsMessage(call.argsInvalid) },
|
|
9755
|
+
isError: true,
|
|
9756
|
+
phaseRejected: false,
|
|
9757
|
+
};
|
|
9758
|
+
}
|
|
9561
9759
|
// Codex-family same-args dedup guard (fix L-2). Scope is
|
|
9562
9760
|
// EXPLORATORY_TOOLS only — repeating Bash/RunShell/Edit/Write
|
|
9563
9761
|
// is often legitimate (retry after a fix, apply-then-verify,
|
|
@@ -10639,11 +10837,14 @@ export async function streamLLMWithTools(
|
|
|
10639
10837
|
});
|
|
10640
10838
|
}
|
|
10641
10839
|
const emittedText = synthesizedText ?? noticeWithFallback;
|
|
10642
|
-
const
|
|
10840
|
+
const visibleText = finalizeVisibleAssistantText(
|
|
10643
10841
|
appendFinalSynthesisNotice(fullText, emittedText),
|
|
10644
10842
|
emittedText,
|
|
10645
10843
|
loopTermination === 'aborted' ? false : sawToolRound,
|
|
10646
10844
|
);
|
|
10845
|
+
const finalText = loopTermination === 'budget-exhausted' && synthesizedText === null
|
|
10846
|
+
? `${buildNoFinalSynthesisLead(loopTermination, toolCallHistory.length)}\n\n${visibleText}`
|
|
10847
|
+
: visibleText;
|
|
10647
10848
|
// Skip post-emit when synthesis was already streamed live AND
|
|
10648
10849
|
// finalText matches synthesizedText. Emit when synthesis failed
|
|
10649
10850
|
// (fallback notice) OR finalization enriched the text.
|
|
@@ -10788,13 +10989,22 @@ function makeOpenAICompatProvider(
|
|
|
10788
10989
|
if (!apiKey && !grokSub) {
|
|
10789
10990
|
throw new Error(`${name} unavailable: configure apiKey via \`elanous setup\``);
|
|
10790
10991
|
}
|
|
10791
|
-
const
|
|
10992
|
+
const activeModel = opts.model || model;
|
|
10993
|
+
const tools = toOpenAITools(opts.tools, name === 'openrouter' && openRouterNeedsKimiToolSchema(openRouterWireModel(activeModel)));
|
|
10994
|
+
const deepSeek = name === 'openrouter' && isOpenRouterDeepSeekWireModel(openRouterWireModel(activeModel));
|
|
10995
|
+
// OR-TOOLCHOICE-PASS (2026-10-10) — OpenRouter 경로만 호출자 toolChoice 를 싣는다.
|
|
10996
|
+
// ⛔ grok/openai 호환 경로는 손대지 않는다(무회귀). toolChoice 가 없거나 tools 가 없으면 키 자체를 안 싣는다.
|
|
10997
|
+
const toolChoice = name === 'openrouter' && tools
|
|
10998
|
+
? openRouterToolChoice(openRouterWireModel(activeModel), opts.toolChoice)
|
|
10999
|
+
: undefined;
|
|
11000
|
+
if (toolChoice !== undefined) {
|
|
11001
|
+
debug.log('llm.openrouter', 'tool-choice-sent', { model: openRouterWireModel(activeModel), requested: opts.toolChoice, toolChoice });
|
|
11002
|
+
}
|
|
10792
11003
|
// Image-pipeline P3.5 — gate the synthetic follow-up workaround
|
|
10793
11004
|
// on the userMessage axis for the active model + brand. `name`
|
|
10794
11005
|
// is 'grok' or 'openai' for makeOpenAICompatProvider callers.
|
|
10795
11006
|
// P-3 §6.9 (2026-05-07) — same lookup also gates user-message
|
|
10796
11007
|
// image blocks in the wire.
|
|
10797
|
-
const activeModel = opts.model || model;
|
|
10798
11008
|
const brand = name as Parameters<typeof isVisionCapableModel>[0];
|
|
10799
11009
|
const followup = isVisionCapableModel(brand, activeModel, 'userMessage');
|
|
10800
11010
|
// 구독이 있으면 «엔드포인트와 자격이 통째로» 바뀐다(cli-chat-proxy + Bearer).
|
|
@@ -10806,16 +11016,45 @@ function makeOpenAICompatProvider(
|
|
|
10806
11016
|
if (useSub) {
|
|
10807
11017
|
debug.log('llm.grok', 'credential', { kind: useSub.kind, source: useSub.source, baseUrl: useSub.baseUrl, via: 'compat-provider' });
|
|
10808
11018
|
}
|
|
11019
|
+
let wireMessages = messages.flatMap((m) => toOpenAIMessages(m, {
|
|
11020
|
+
acceptToolImagesViaFollowup: followup,
|
|
11021
|
+
acceptUserMessageImages: followup,
|
|
11022
|
+
...(name === 'openrouter' ? { echoReasoningDetails: true } : {}),
|
|
11023
|
+
...(deepSeek ? { deepSeekReplay: true } : {}),
|
|
11024
|
+
}));
|
|
11025
|
+
// OR-DEEPSEEK-TUNE — deepseek/* 만: 설정 기본값의 상류 고정(명시 라우팅이 없을 때) ⊕ 관측 `deepseek-replay`.
|
|
11026
|
+
const deepSeekProvider = deepSeek ? openRouterDeepSeekRequestExtras(openRouterWireModel(activeModel), wireMessages,
|
|
11027
|
+
(wire.extraBody as { provider?: unknown } | undefined)?.provider, cfg.openrouter?.providerPreferences, cfg.openrouter?.upstreamPins) : {};
|
|
11028
|
+
// OR-ANTHROPIC-CACHE (2026-10-10) — OpenRouter 뒤 anthropic/* · moonshotai/* 만 cache_control 중단점을 싣는다.
|
|
11029
|
+
// ⛔ 다른 OpenRouter 모델과 grok/openai/local 호환 경로는 이 분기를 안 탄다 — 본문 바이트 동일(무회귀).
|
|
11030
|
+
const cacheFamily = name === 'openrouter' ? openRouterPromptCacheFamily(openRouterWireModel(activeModel)) : null;
|
|
11031
|
+
if (cacheFamily) {
|
|
11032
|
+
if (opts.promptCache === false) {
|
|
11033
|
+
debug.log('llm.openrouter', 'prompt-cache', { model: openRouterWireModel(activeModel), applied: false, reason: 'promptCache:false' });
|
|
11034
|
+
} else {
|
|
11035
|
+
const { getDefaultCacheTTL } = await import('./config.js');
|
|
11036
|
+
const ttl = opts.promptCacheTTL ?? getDefaultCacheTTL();
|
|
11037
|
+
const plan = applyOpenRouterCacheControl(wireMessages, { family: cacheFamily, ttl });
|
|
11038
|
+
wireMessages = plan.messages;
|
|
11039
|
+
debug.log('llm.openrouter', 'prompt-cache', {
|
|
11040
|
+
model: openRouterWireModel(activeModel), applied: plan.breakpoints > 0, family: cacheFamily,
|
|
11041
|
+
ttl: cacheFamily === 'anthropic' ? ttl : '5m',
|
|
11042
|
+
breakpoints: plan.breakpoints, system: plan.systemBreakpoints, tail: plan.tailBreakpoints,
|
|
11043
|
+
});
|
|
11044
|
+
}
|
|
11045
|
+
}
|
|
11046
|
+
// OR-STICKY-ROUTING (2026-10-10) — 같은 세션/런의 요청을 같은 상류로 고정해 캐시 적중을 지킨다.
|
|
11047
|
+
// ⛔ openrouter 만, 그리고 키가 있을 때만 싣는다 — 키가 없거나 다른 provider 면 본문·헤더 바이트 동일(무회귀).
|
|
11048
|
+
const sticky = name === 'openrouter' ? openRouterStickySessionKey(opts.sessionId, process.env.ELANOUS_RUN_ID) : null;
|
|
11049
|
+
if (sticky) {
|
|
11050
|
+
debug.log('llm.openrouter', 'sticky-routing', { model: openRouterWireModel(activeModel), source: sticky.source, hashed: sticky.hashed });
|
|
11051
|
+
}
|
|
10809
11052
|
yield* streamOpenAIEvents(
|
|
10810
11053
|
useSub ? `${useSub.baseUrl}/chat/completions` : resolvedUrl,
|
|
10811
11054
|
useSub ? useSub.token : apiKey,
|
|
10812
11055
|
{
|
|
10813
11056
|
model: wire.model ? wire.model(activeModel) : activeModel,
|
|
10814
|
-
messages:
|
|
10815
|
-
acceptToolImagesViaFollowup: followup,
|
|
10816
|
-
acceptUserMessageImages: followup,
|
|
10817
|
-
...(name === 'openrouter' ? { echoReasoningDetails: true } : {}),
|
|
10818
|
-
})),
|
|
11057
|
+
messages: wireMessages,
|
|
10819
11058
|
...(() => {
|
|
10820
11059
|
const fields = openAiCompatSamplingFields(brand, activeModel, opts.temperature ?? 0.3, opts.maxTokens ?? 2048);
|
|
10821
11060
|
// ⛔ 2026-09-23 — OpenRouter 뒤의 추론 모델(kimi·glm·qwen …)은 기본 0.3 을 강제하면 안 된다:
|
|
@@ -10829,10 +11068,17 @@ function makeOpenAICompatProvider(
|
|
|
10829
11068
|
return fields;
|
|
10830
11069
|
})(),
|
|
10831
11070
|
...(tools ? { tools } : {}),
|
|
11071
|
+
...(toolChoice !== undefined ? { tool_choice: toolChoice } : {}),
|
|
10832
11072
|
...(wire.extraBody ?? {}),
|
|
11073
|
+
...deepSeekProvider,
|
|
11074
|
+
// OpenRouter alone resolves per-call effort against the configured level and catalog default.
|
|
11075
|
+
...(name === 'openrouter'
|
|
11076
|
+
? openRouterReasoningField(activeModel, opts.reasoningEffort, cfg.reasoningLevel)
|
|
11077
|
+
: {}),
|
|
11078
|
+
...(sticky ? { session_id: sticky.key } : {}),
|
|
10833
11079
|
},
|
|
10834
11080
|
opts.signal,
|
|
10835
|
-
useSub ? useSub.headers : wire.headers,
|
|
11081
|
+
useSub ? useSub.headers : (sticky ? { ...wire.headers, 'x-session-id': sticky.key } : wire.headers),
|
|
10836
11082
|
);
|
|
10837
11083
|
},
|
|
10838
11084
|
async *chat(messages, opts = {}) { yield* textOnly(this.streamChat!(messages, opts)); },
|
|
@@ -10852,7 +11098,18 @@ function makeOpenRouterProvider(cfg: UCLLMConfig): LLMProvider {
|
|
|
10852
11098
|
OPENROUTER_API_URL,
|
|
10853
11099
|
{ ...cfg, apiKey: cfg.apiKey || getOpenRouterApiKey() },
|
|
10854
11100
|
// ⭐ BACKLOG C7 — `usage:{include:true}` 면 마지막 청크 `usage.cost` 에 «실제 청구액»이 온다(추정 아님).
|
|
10855
|
-
{
|
|
11101
|
+
{
|
|
11102
|
+
model: openRouterWireModel, headers: { 'X-Title': 'elanous' }, omitDefaultTemperature: true, omitMaxTokens: true,
|
|
11103
|
+
extraBody: {
|
|
11104
|
+
usage: { include: true },
|
|
11105
|
+
provider: {
|
|
11106
|
+
require_parameters: true,
|
|
11107
|
+
allow_fallbacks: true,
|
|
11108
|
+
...(cfg.openrouter?.providerPreferences && typeof cfg.openrouter.providerPreferences === 'object' && !Array.isArray(cfg.openrouter.providerPreferences)
|
|
11109
|
+
? cfg.openrouter.providerPreferences : {}),
|
|
11110
|
+
},
|
|
11111
|
+
},
|
|
11112
|
+
},
|
|
10856
11113
|
);
|
|
10857
11114
|
// ⛔ 2026-09-23 — OpenRouter 의 `max_tokens` 는 «추론 토큰까지» 센다. 호환 경로 기본값 2048 이면 추론 모델이
|
|
10858
11115
|
// 본문·도구 호출에 닿기 전에 잘렸다(실측 glm-5.3: 2048 → finish=length). 오전 판은 바닥 16384 를 뒀고,
|
|
@@ -10861,11 +11118,82 @@ function makeOpenRouterProvider(cfg: UCLLMConfig): LLMProvider {
|
|
|
10861
11118
|
return inner;
|
|
10862
11119
|
}
|
|
10863
11120
|
|
|
11121
|
+
/** OR-TOOLARGS-REPAIR — 깨진 도구 인자 호출에 돌려주는 오류 문면(도구는 실행되지 않았다). */
|
|
11122
|
+
export function buildInvalidToolArgsMessage(info: ToolArgsInvalid): string {
|
|
11123
|
+
const truncated = info.finishReason === 'length';
|
|
11124
|
+
return `tool arguments were not valid JSON (${info.chars} chars` +
|
|
11125
|
+
(info.finishReason ? `, finish_reason=${info.finishReason}` : '') +
|
|
11126
|
+
`${truncated ? ' — the output was cut off at the length limit' : ' — truncated or malformed?'}). ` +
|
|
11127
|
+
'The tool was NOT executed. Re-issue the call with complete, valid JSON arguments' +
|
|
11128
|
+
(truncated ? ' (keep the payload smaller, e.g. split a large write into several calls).' : '.');
|
|
11129
|
+
}
|
|
11130
|
+
|
|
11131
|
+
/** OR-TOOLCHOICE-PASS — LLMOpts.toolChoice → OpenRouter `tool_choice` (`toChatToolChoice` 재사용).
|
|
11132
|
+
* ⚠️ Kimi(moonshotai/*)는 thinking 모드에서 강제 선택(required·특정 도구)을 400 으로 거부한다
|
|
11133
|
+
* (openclaw moonshot-thinking.ts:100-108 와 같은 처리) ⇒ 강제는 'auto' 로 내린다. */
|
|
11134
|
+
export function openRouterToolChoice(wireModel: string, tc: ToolChoice | undefined): unknown {
|
|
11135
|
+
const chat = toChatToolChoice(tc);
|
|
11136
|
+
if (chat === undefined) return undefined;
|
|
11137
|
+
if (wireModel.startsWith('moonshotai/') && chat !== 'auto' && chat !== 'none') return 'auto';
|
|
11138
|
+
return chat;
|
|
11139
|
+
}
|
|
11140
|
+
|
|
11141
|
+
/** OR-STICKY-ROUTING — OpenRouter 고정 라우팅 키. 본문 최상위 `session_id` ⊕ 헤더 `x-session-id` 로 싣는다
|
|
11142
|
+
* (hermes plugins/model-providers/openrouter build_extra_body: 본문 session_id 를 «라우팅 키»로 직접 쓰고 첫 성공
|
|
11143
|
+
* 요청부터 고정 · openclaw openai-completions-transport: openrouter 는 `x-session-id` 헤더 — `x-session-affinity` 는
|
|
11144
|
+
* openrouter 가 아닌 호환 게이트웨이용이라 여기선 안 쓴다).
|
|
11145
|
+
* 키 우선순위: 호출자의 대화 `sessionId` → 하니스 런 `ELANOUS_RUN_ID`. 둘 다 없으면 null(아무것도 안 싣는다).
|
|
11146
|
+
* 128자를 넘거나 허용 밖 문자가 있으면 sha256 앞 32자로 접는다(원문 id 를 상류에 안 흘린다는 부수 효과). */
|
|
11147
|
+
export function openRouterStickySessionKey(
|
|
11148
|
+
sessionId: string | undefined,
|
|
11149
|
+
runId: string | undefined,
|
|
11150
|
+
): { key: string; source: 'session' | 'run'; hashed: boolean } | null {
|
|
11151
|
+
// 공백뿐이면 «없음». 검사·해시는 원문 그대로 — 다듬으면 ' sess ' 와 'sess' 가 같은 키가 된다.
|
|
11152
|
+
const s = sessionId && sessionId.trim() ? sessionId : undefined;
|
|
11153
|
+
const r = runId && runId.trim() ? runId : undefined;
|
|
11154
|
+
const raw = s ?? r;
|
|
11155
|
+
if (!raw) return null;
|
|
11156
|
+
const source = s ? 'session' : 'run';
|
|
11157
|
+
if (raw.length <= 128 && /^[A-Za-z0-9._:-]+$/.test(raw)) return { key: raw, source, hashed: false };
|
|
11158
|
+
return { key: `elanous-${createHash('sha256').update(raw).digest('hex').slice(0, 32)}`, source, hashed: true };
|
|
11159
|
+
}
|
|
11160
|
+
|
|
10864
11161
|
/** `openrouter/moonshotai/kimi-k3` → `moonshotai/kimi-k3`. 접두가 없으면 그대로. */
|
|
10865
11162
|
export function openRouterWireModel(model: string): string {
|
|
10866
11163
|
return model.startsWith('openrouter/') ? model.slice('openrouter/'.length) : model;
|
|
10867
11164
|
}
|
|
10868
11165
|
|
|
11166
|
+
/** OpenRouter effort: call > resolved config (including escalation) > open-weight default.
|
|
11167
|
+
* Keep the existing effort mapping; Claude-family models use verbosity instead of reasoning. */
|
|
11168
|
+
const OPENROUTER_REASONING_EFFORT: Record<string, 'low' | 'medium' | 'high'> = {
|
|
11169
|
+
minimal: 'low', low: 'low', medium: 'medium', high: 'high', xhigh: 'high', max: 'high',
|
|
11170
|
+
};
|
|
11171
|
+
function openRouterReasoningField(
|
|
11172
|
+
model: string, requested: string | undefined, configured: UCLLMConfig['reasoningLevel'],
|
|
11173
|
+
): { reasoning?: { effort: 'low' | 'medium' | 'high' | 'xhigh' }; verbosity?: 'low' | 'medium' | 'high' } {
|
|
11174
|
+
const wireModel = openRouterWireModel(model);
|
|
11175
|
+
// The catalog's model-specific open-weight verdict, not a vendor/slug prefix,
|
|
11176
|
+
// gates the default: an unregistered release may be closed-weight.
|
|
11177
|
+
const slug = wireModel.slice(wireModel.indexOf('/') + 1);
|
|
11178
|
+
const openWeight = wireModel.includes('/') && BUILTIN_CATALOG.models.some(
|
|
11179
|
+
(entry) => entry.id === slug && entry.openWeight === true,
|
|
11180
|
+
);
|
|
11181
|
+
const configEffort = configured === 'off' ? undefined : configured;
|
|
11182
|
+
// OR-DEEPSEEK-TUNE — deepseek/* 의 기본은 카탈로그 손 레코드(YAML `reasoning`) · 없으면 아래 기존 폴백.
|
|
11183
|
+
const catalogEffort = requested === undefined && configured === undefined ? openRouterDeepSeekCatalogEffort(model) : undefined;
|
|
11184
|
+
const source = requested !== undefined ? 'call' : configured !== undefined ? 'config' : catalogEffort ? 'catalog' : openWeight ? 'default' : 'none';
|
|
11185
|
+
const effort = requested ?? (configured !== undefined ? configEffort : catalogEffort ?? (openWeight ? 'medium' : undefined));
|
|
11186
|
+
// OR-DEEPSEEK-TUNE — DeepSeek V4 는 자기 표(xhigh·max→xhigh · off→칸 없음 · src/llm/openrouter-deepseek.ts).
|
|
11187
|
+
const deepSeekEffort = openRouterDeepSeekEffort(wireModel, effort);
|
|
11188
|
+
const sent = deepSeekEffort !== undefined ? (deepSeekEffort ?? undefined)
|
|
11189
|
+
: effort !== undefined && Object.hasOwn(OPENROUTER_REASONING_EFFORT, effort)
|
|
11190
|
+
? OPENROUTER_REASONING_EFFORT[effort] : undefined;
|
|
11191
|
+
const field = sent ? (wireModel.startsWith('anthropic/') ? 'verbosity' : 'reasoning') : 'none';
|
|
11192
|
+
debug.log('llm.openrouter', 'reasoning', { model, requested: requested ?? null, sent: sent ?? null, source, field });
|
|
11193
|
+
return field === 'verbosity' ? { verbosity: sent as 'low' | 'medium' | 'high' }
|
|
11194
|
+
: field === 'reasoning' ? { reasoning: { effort: sent! } } : {};
|
|
11195
|
+
}
|
|
11196
|
+
|
|
10869
11197
|
/** Codex-specific provider. Prefers OAuth tokens from ~/.config/elanous/auth.json
|
|
10870
11198
|
* (refreshing them when within the 120s buffer) and falls back to the
|
|
10871
11199
|
* plain apiKey flow only when no tokens are on file. OAuth mode targets
|
|
@@ -11210,6 +11538,7 @@ export function inferProviderFromModel(model: string | undefined): string | null
|
|
|
11210
11538
|
* its own configured default. */
|
|
11211
11539
|
export function isModelCompatible(providerName: string, model: string | undefined): boolean {
|
|
11212
11540
|
if (!model) return true;
|
|
11541
|
+
if (providerName === 'bedrock') return isBedrockCompatibleModel(model, inferProviderFromModel);
|
|
11213
11542
|
const implied = inferProviderFromModel(model);
|
|
11214
11543
|
if (implied === null) return true; // unknown prefix — let provider handle
|
|
11215
11544
|
// openai-codex and openai accept each other's model families (gpt-*, codex-*).
|
|
@@ -11249,7 +11578,7 @@ export function anyProviderAvailable(userConfig?: UserConfig): boolean {
|
|
|
11249
11578
|
} catch { return false; }
|
|
11250
11579
|
}
|
|
11251
11580
|
} catch { /* fall through to env check */ }
|
|
11252
|
-
return Object.values(PROVIDERS).some(p => p.available());
|
|
11581
|
+
return Object.values(PROVIDERS).some(p => p.name !== 'bedrock' && p.available()); // bedrock 은 auto 후보가 아니다
|
|
11253
11582
|
}
|
|
11254
11583
|
|
|
11255
11584
|
/** 직결 배선이 없는 계열 → OpenRouter 에서 그 벤더의 대표 모델(사다리 `openrouter` 에 선 것). */
|
|
@@ -11266,8 +11595,16 @@ export function getProviderForConfig(
|
|
|
11266
11595
|
model?: string,
|
|
11267
11596
|
): LLMProvider {
|
|
11268
11597
|
const { provider } = userConfig.llm;
|
|
11598
|
+
// CLAUDE-IMPL-LANE(10-11) — `claude-acp` 는 LLM provider 가 아니라 구독 ACP 구현 실행기 선택이다.
|
|
11599
|
+
// 여기서 풀리면 모델 이름(claude-…)이 anthropic(API 키 provider)으로 넘어가 «구독» 런이 API 로 과금된다 → 거부.
|
|
11600
|
+
// 구현은 implement seam 의 claude-acp 갈래(src/self-implement/claude-acp-implement.ts)만 쓴다.
|
|
11601
|
+
if ((provider as string) === 'claude-acp') {
|
|
11602
|
+
throw new Error('claude-acp 는 LLM provider 가 아니다 — 구독 ACP 구현 레인 전용(src/self-implement/claude-acp-implement.ts) · API provider 로 풀지 않는다');
|
|
11603
|
+
}
|
|
11269
11604
|
// ⛔ 2026-09-23 — `kimi`·`qwen`·`glm` 은 union·사다리에 있지만 «직결» 배선이 없다(사다리 `wip`).
|
|
11270
11605
|
// 종전엔 `unknown provider: kimi` 로 «아무것도» 안 말하고 죽었다. 이제 실제로 도는 길이 있다(`openrouter`).
|
|
11606
|
+
// ZAI-CODING-PLAN-PROVIDER(대표 10-11) — `ZAI_API_KEY` 가 있을 때만 glm 직결. 없으면 아래 안내 그대로(src/llm/zai-coding-plan.ts).
|
|
11607
|
+
if (provider === 'glm' && zaiCodingPlanAvailable()) return makeZaiCodingPlanProvider({ ...userConfig.llm, model: model || userConfig.llm.model });
|
|
11271
11608
|
const direct = OPENROUTER_ROUTE_FOR_WIP_PROVIDER[provider as keyof typeof OPENROUTER_ROUTE_FOR_WIP_PROVIDER];
|
|
11272
11609
|
if (direct) {
|
|
11273
11610
|
throw new Error(
|
|
@@ -11291,6 +11628,10 @@ export function getProviderForConfig(
|
|
|
11291
11628
|
if (!isKnownProviderName(resolvedProviderName)) {
|
|
11292
11629
|
throw new Error(`unknown provider: ${resolvedProviderName}`);
|
|
11293
11630
|
}
|
|
11631
|
+
if (resolvedProviderName === 'openrouter') {
|
|
11632
|
+
// Preserve the requesting config for OpenRouter, not the config-free singleton.
|
|
11633
|
+
return makeOpenRouterProvider({ provider: 'openrouter', model: decision.model, reasoningLevel: userConfig.llm.reasoningLevel });
|
|
11634
|
+
}
|
|
11294
11635
|
return PROVIDERS[resolvedProviderName]!;
|
|
11295
11636
|
}
|
|
11296
11637
|
if (!isKnownProviderName(resolvedProviderName)) {
|
|
@@ -11330,9 +11671,10 @@ export function getProviderForConfig(
|
|
|
11330
11671
|
case 'openai-codex':
|
|
11331
11672
|
return makeCodexProvider(llm);
|
|
11332
11673
|
case 'openrouter':
|
|
11333
|
-
return makeOpenRouterProvider(userConfig.llm.provider === 'openrouter' ? llm : { provider: 'openrouter', model: decision.model });
|
|
11674
|
+
return makeOpenRouterProvider(userConfig.llm.provider === 'openrouter' ? llm : { provider: 'openrouter', model: decision.model, reasoningLevel: llm.reasoningLevel });
|
|
11334
11675
|
case 'anthropic':
|
|
11335
11676
|
return makeAnthropicProvider(llm);
|
|
11677
|
+
case 'bedrock': return makeBedrockProvider(llm);
|
|
11336
11678
|
case 'gemini':
|
|
11337
11679
|
// Wave 1 (2026-05-04) — native @google/genai SDK. Previously
|
|
11338
11680
|
// makeOpenAICompatProvider tunnel which couldn't carry
|