elanous 0.2.21 → 0.2.23
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/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-b23d2e92161d11fd.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-fbef064c213b2b18.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-d5341ac96203a983.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-0160ab83c8685a12.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-55c631c032dcc47e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-ad3bd8084048bee4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-e6784759a2531031.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-5c5d0e370f495ef6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-c325e21543cd48a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/{page-111cabe4d1fd69ae.js → page-6168a7c43e6ef8f5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-31417d3604154a6d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-e9606dc0bdec9305.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-a648bc464c9dc754.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-25bb425afdb27541.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-32d72fdef1afe11a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-d27b794c8ba76bbb.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-2bd9ce9c020d02d4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-a34096245e63b9f2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-22170f4f00a15496.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-4cc66d22ca4ec502.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-83b14c729fcea837.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-6e2781c523dad761.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-26dd415c8f13f341.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-ccdb83ed40c8d724.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-7ad3de8fa06fdea9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-015c02c4fec4023e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-6b0ae5b5c42f6d2f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-786111f30b6f0969.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-48fb31810693c357.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4e17cce5e2ed0fee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-cb154acadb025414.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-16258e956ea93fc2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-c2dd2b19c93f90ab.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-85f35dd1dd96ae87.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-d3c007c8a0ddd7ee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-7837ce2aacb97b04.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-7350ee93f4fe1033.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-00723458575f2b19.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-745d9b6c015076f8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-736d33c7414a8a1a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-119be9a0444d2482.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-fa806c018833e332.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-c782041b5f5199ba.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-d431fbdea6ad93dd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-0c056abff82b9891.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-242d668e4fbf72c4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-847c3de6ca8a4416.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-81dd0d8ae923ed72.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-74e69ba2c8e970d4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-70038f41ae7cf931.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/5619d59e87eddf66.css +1 -0
- package/apps/pwa/out/_next/static/css/d0a48dc099ed86cf.css +1 -0
- package/apps/pwa/out/_next/static/{MObU8ujkMciAKr6ljAV05 → rfkMm4movqkqMebBrCXiR}/_buildManifest.js +1 -1
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +23 -23
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +23 -23
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +23 -23
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +22 -22
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +22 -22
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +23 -23
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +22 -22
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +23 -23
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +23 -23
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +22 -22
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +23 -23
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +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/graphs/catalog/catalog.yaml +1 -1
- package/graphs/drafts/recipes.yaml +2 -2
- package/graphs/log-horizon/log-horizon-watch.yaml +25 -0
- package/graphs/log-horizon/recipes.yaml +3 -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/graphs/test-diet/recipes.yaml +3 -0
- package/graphs/test-diet/test-diet.yaml +3 -1
- package/package.json +4 -1
- package/scripts/bench-report.ts +82 -3
- package/scripts/ci-typecheck-changed.ts +10 -1
- package/scripts/f-session-monitor.ts +69 -0
- package/scripts/hq/hq-fence-wrapper.sh +148 -0
- package/scripts/hq/standby-snapshot.ts +7 -3
- package/scripts/knowledge-compress.ts +11 -0
- package/scripts/lib/typecheck-ratchet.ts +51 -0
- package/scripts/nightly-docops.ts +90 -3
- package/scripts/openai-relay-server.ts +5 -1
- package/scripts/release-loop/docs-node.ts +258 -43
- package/scripts/release-loop/gate-method.ts +59 -0
- package/scripts/release-loop/gate-node.ts +73 -7
- 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 +34 -4
- package/scripts/release-loop/resume.ts +53 -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 +8 -1
- package/scripts/research-coo-admin-dates.ts +39 -0
- package/scripts/rhythm/daily.ts +51 -2
- package/scripts/rhythm/weekly.ts +3 -2
- package/scripts/skills/public-check.ts +7 -2
- package/scripts/smart-merge/resync-shadow.ts +5 -3
- package/scripts/test-diet/lib.ts +81 -1
- package/scripts/test-diet/node.ts +48 -2
- package/scripts/tsc-main-safety-net.ts +189 -0
- package/scripts/usage-rollup.ts +8 -4
- package/scripts/verify-coo-admin-evidence.ts +83 -0
- package/src/acp/client.ts +4 -2
- package/src/acp/codex-plugins.ts +48 -6
- package/src/agent/monad-agent-turn.ts +67 -5
- package/src/agent/run-context.ts +14 -0
- package/src/agent/tool-profile.ts +28 -2
- package/src/agent-env/profile.ts +25 -5
- package/src/agent-mission/acp-judge.ts +8 -2
- package/src/agent-mission/capabilities-cli.ts +16 -1
- package/src/agent-mission/driver.ts +27 -13
- package/src/agent-mission/pr-review-watch.ts +6 -2
- package/src/agent-mission/review-loop.ts +33 -5
- package/src/agent-mission/supervisor-metrics.ts +17 -2
- package/src/agent-substrate/acp-reviewer.ts +25 -9
- package/src/agent-substrate/pr-reviewer.ts +175 -32
- package/src/agent-substrate/review-intent.ts +106 -5
- package/src/agent-substrate/self-review-cli.ts +111 -16
- 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 +238 -20
- 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/pr-manager.ts +30 -11
- package/src/away/release-watch.ts +47 -8
- package/src/boot/acp-server.ts +4 -7
- package/src/boot/acp-socket-path.ts +7 -0
- package/src/briefing/brief-items.ts +123 -22
- package/src/chat/index.ts +13 -3
- package/src/cli/agent-cli.ts +20 -0
- package/src/cli/brief-cli.ts +46 -22
- package/src/cli/cli-user-error.ts +9 -2
- package/src/cli/config-classify.ts +83 -0
- package/src/cli/control-cli.ts +14 -0
- package/src/cli/decisions-cli.ts +26 -16
- package/src/cli/log-event-names.ts +3 -0
- package/src/cli/logs-cli.ts +1 -0
- package/src/cli/logs-model-input.ts +1 -1
- 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 +94 -9
- package/src/cli/pr-land-overlap-evidence.ts +131 -0
- package/src/cli/release-cli.ts +74 -15
- package/src/cli/self-update.ts +173 -10
- package/src/cli/skills-cli.ts +12 -3
- package/src/cli/tasks-cli.ts +241 -28
- package/src/connectors/types.ts +6 -6
- package/src/context-bus/context-first.ts +51 -2
- package/src/context-bus/context-now-surfaces.ts +29 -0
- package/src/context-bus/coord-events.ts +32 -4
- package/src/context-bus/long-term-memory.ts +26 -7
- package/src/context-bus/nightly-condense.ts +170 -21
- package/src/control/control-status.ts +87 -0
- package/src/control-plane/light-member.ts +5 -3
- package/src/control-plane/member.ts +172 -7
- package/src/core-turn/run-goal-loop.ts +108 -3
- package/src/dashboard/chat-fold.ts +20 -0
- package/src/dashboard/first-screen-band.ts +151 -1
- package/src/dashboard/index.ts +27 -5
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +14 -3
- package/src/dashboard/stale-install-check.ts +13 -2
- package/src/dashboard/turn-stream-formatter.ts +25 -0
- package/src/debug/log-diet.ts +159 -0
- package/src/debug/log.ts +52 -17
- package/src/decisions/decision-cards.ts +20 -1
- package/src/decisions/decision-ledger.ts +11 -8
- package/src/decisions/web-push-decision-cards.ts +19 -3
- package/src/discord-self-message.ts +2 -2
- package/src/display/coordinator.ts +25 -2
- package/src/domains/coo-admin-dates.evidence.json +876 -0
- package/src/domains/coo-admin-tool.ts +75 -14
- package/src/domains/cron-match.ts +1 -0
- package/src/domains/ops-status.ts +53 -0
- package/src/domains/outbound-alert.ts +41 -7
- package/src/domains/release-tool.ts +119 -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/exec-requests/planner.ts +6 -0
- 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 +1 -0
- package/src/graph-kinds/registry.ts +6 -6
- package/src/graph-runner/graph-cli.ts +34 -2
- package/src/graph-runner/graph-run-api.ts +7 -0
- package/src/graph-runner/graph-tick.ts +73 -12
- package/src/graph-runner/runner.ts +94 -13
- package/src/graph-unify/wf-to-graph.ts +79 -0
- package/src/graph-wizard/generate.ts +34 -2
- package/src/graph-wizard/steps.ts +13 -0
- package/src/harness/dispatch-backpressure.ts +259 -0
- package/src/harness/harness-cli-command.ts +227 -50
- package/src/harness/harness-queue.ts +58 -14
- package/src/harness/harness-seams.ts +2 -20
- package/src/harness/harness-substrate-default.ts +72 -1
- package/src/harness/launch-advice.ts +23 -0
- package/src/harness/nested-elanous-policy.ts +4 -2
- package/src/hq/fence-wrapper.ts +7 -0
- package/src/hq/hq.ts +33 -2
- package/src/hq/lease.ts +13 -0
- package/src/hq/seats.ts +114 -18
- package/src/index.ts +199 -71
- 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/intelligence-map/model-alias.ts +6 -0
- package/src/intelligence-map/model-catalog.ts +41 -0
- package/src/knowledge/conclusion-compress.ts +93 -0
- package/src/knowledge/kgs/pack.ts +5 -2
- package/src/knowledge/kgs/sqlite-store.ts +15 -0
- package/src/knowledge/know-find.ts +9 -2
- package/src/knowledge/query.ts +20 -0
- package/src/knowledge/tools/knowledge-query.ts +20 -2
- package/src/knowledge/write.ts +234 -2
- package/src/llm/bedrock-provider.ts +175 -0
- package/src/llm/bedrock.ts +345 -0
- package/src/llm/provider-credentials.ts +3 -1
- package/src/llm.ts +332 -51
- package/src/loops/budget.ts +150 -0
- package/src/loops/neighbor-runtime.ts +88 -0
- package/src/loops/orchestrator/author-depth.ts +29 -11
- package/src/loops/orchestrator/overlap.ts +7 -1
- package/src/loops/orchestrator/resync-shadow.ts +1 -1
- package/src/loops/orchestrator/seat-share.ts +6 -49
- package/src/loops/orchestrator/tick.ts +35 -2
- package/src/loops/orchestrator/traffic.ts +6 -80
- package/src/loops/registry.ts +5 -0
- package/src/market/publish.ts +17 -1
- package/src/market/signed-index.ts +42 -0
- package/src/maturity/feature-maturity.ts +2 -1
- package/src/mcp/mcp-oauth.ts +136 -17
- package/src/model-tier/llm-tier-map.ts +48 -4
- package/src/models/prompts.ts +22 -1
- package/src/mss/logging/horizon-watch.ts +168 -0
- package/src/mss/logging/log-store.ts +204 -15
- package/src/mss/logging/redaction.ts +17 -0
- 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/draft-metrics.ts +22 -8
- package/src/nexus/api/error-reports.ts +30 -8
- package/src/nexus/api/graph-peer-edit.ts +77 -0
- package/src/nexus/api/graph-wizard-api.ts +9 -1
- package/src/nexus/api/graphs-api.ts +145 -7
- package/src/nexus/api/http-server.ts +101 -8
- package/src/nexus/api/loop-resources.ts +42 -0
- package/src/nexus/api/outbound-report.ts +8 -3
- package/src/nexus/api/plugins-market.ts +24 -0
- package/src/nexus/api/telegram-trigger-bot.ts +6 -3
- package/src/nexus/index.ts +13 -2
- package/src/nexus/outbound/format.ts +2 -0
- package/src/nexus/outbound/router.ts +198 -13
- package/src/oauth/claude-pty-maturity.ts +24 -0
- package/src/oauth/codex-account-rotation.ts +16 -18
- package/src/oauth/codex-account-store.ts +134 -5
- package/src/oauth/fallback-chain.ts +50 -15
- package/src/onboarding.ts +2 -1
- 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/market-bundle.ts +9 -0
- package/src/plugins/maker/plugin-maker.ts +32 -21
- package/src/plugins/maker/wizard-generate.ts +87 -9
- package/src/policy/llm-policy.ts +24 -6
- package/src/process/pid-liveness.ts +1 -1
- package/src/prompt-cache/openai.ts +10 -6
- package/src/prompt-cache/openrouter.ts +94 -0
- package/src/prompt-enhance/enhance.ts +46 -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-board.ts +27 -0
- package/src/release-loop/checklist.ts +62 -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 +91 -22
- 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/retro/daily.ts +23 -9
- package/src/seat-address/seat-address.ts +1 -0
- package/src/seat-loop/seat-loop.ts +208 -21
- package/src/seat-loop/seat-report.ts +29 -1
- 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 +157 -11
- package/src/self-dev/dev-pipeline.ts +18 -1
- package/src/self-dev/draft-residue.ts +463 -0
- package/src/self-dev/draft-sweep.ts +195 -17
- package/src/self-dev/draft-triage-rules.ts +27 -1
- 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 +57 -2
- package/src/self-dev/orchestrate-summary-line.ts +13 -0
- package/src/self-dev/orchestrate.ts +9 -133
- package/src/self-dev/review-provider-fallback.ts +179 -0
- package/src/self-dev/run-store.ts +1 -3
- package/src/self-dev/run-supervisor.ts +8 -23
- package/src/self-dev/run-types.ts +178 -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 +2 -4
- package/src/self-implement/blocked-draft-policy.ts +3 -19
- package/src/self-implement/draft-on-stop-mode.ts +18 -0
- package/src/self-implement/follow-up-goals.ts +114 -38
- 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.ts +24 -4
- package/src/self-implement/goal-digest.ts +19 -0
- package/src/self-implement/graph-overlay-condition.ts +4 -0
- package/src/self-implement/harness-policy-gates.ts +7 -5
- package/src/self-implement/headless-elanous-driver.ts +11 -9
- package/src/self-implement/host-regate.ts +148 -43
- package/src/self-implement/l8-merge-queue.ts +147 -13
- 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 +201 -43
- 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/seams.ts +41 -6
- package/src/self-implement/self-implement-cli.ts +6 -0
- 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/shell-env-bootstrap.ts +19 -4
- 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 +20 -9
- package/src/steward/triage.ts +29 -10
- package/src/storage/file-lock.ts +40 -4
- package/src/task-agent/actions.ts +4 -0
- package/src/task-agent/card-evidence.ts +59 -13
- package/src/task-agent/completion-evidence.ts +31 -3
- package/src/task-agent/cover.ts +61 -0
- package/src/task-agent/judge.ts +4 -3
- package/src/task-agent/land-worktree.ts +201 -0
- package/src/task-agent/live-move-history.ts +133 -0
- package/src/task-agent/live-moves.ts +222 -12
- package/src/task-agent/parent-host.ts +117 -8
- package/src/task-agent/rejudge-on-head.ts +297 -0
- package/src/task-agent/review-result-capture.ts +218 -0
- package/src/task-agent/shadow.ts +118 -7
- package/src/task-agent/task-hand.ts +138 -11
- package/src/task-orchestrator/surfaces/pod-child-providers.ts +29 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +6 -3
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +16 -2
- package/src/task-orchestrator/surfaces/pod-image-source.ts +212 -0
- package/src/task-orchestrator/surfaces/pod-lease.ts +93 -12
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +25 -2
- package/src/task-orchestrator/surfaces/pod-pool.ts +203 -28
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +259 -36
- package/src/task-orchestrator/surfaces/self-implement.ts +11 -0
- package/src/telegram-commands.ts +8 -0
- package/src/telegram-project-command.ts +6 -0
- 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 +2 -1
- package/src/user-config.ts +167 -28
- 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/executor.ts +24 -2
- package/src/workflow-runtime/triggers/registry.ts +27 -0
- package/src/workflow-runtime/triggers/schedule-source.ts +30 -3
- package/src/workflow-runtime/triggers/scheduler.ts +1 -0
- 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-c97eba9fb72a9a5e.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-ff55a35b202c0f94.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-995ea9f5ef33d71e.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/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-59fedea50d13c762.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-f1762140ef9a96b1.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-7581825d511a64c0.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/9497-b0e758d1cd4ae8d7.js +0 -1
- 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-937c92292a4ab4f0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-d781be3e3a9cfd74.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-b0a80997903852d8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-2b1263165630d9c8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-ea998f7f5d156bea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-33c328b64ca508f8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-e2d6bed48ac20120.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-544dd4bd4847eeb7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-3ee191319bf97d87.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-e4bcb2c503dab04b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-300897dcbbd5ed76.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-a449f1ed472b81c2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-9045094d6d3b5cd0.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-c06673596849ef45.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-103fa3191c1b2e08.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-9f81233f29dcd409.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-be8b4615c919e36c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-c685b104e0dfa609.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-8d693331cfbb6add.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-cef4f30a4c22fae1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66ea1b54fc83fa15.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-7a12f61be4a579d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-c85b0589591a99c9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-725a4da02dd129eb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-8cc707bd09a497d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-90b55be1f15ce0e8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-cb16606e08be65db.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-16dc64b74ed6a40a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-21bec4afeb2f0917.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-dc39ee7a36d26385.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-84ae759f76053672.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-3db58ddb61fe2be9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c5315e30f3528dc4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-2fe368efb6de3b6a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8d04132dd0ac5e10.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-f23484de467c9ea3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-c69762987b751174.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-5456692bda39aafb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-d75f7cd65845ce98.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-5603f5e568b25ce3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-d2cc0f4e89f42028.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-a6eb73b8a4840f1c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-c0a3f4d10edb83fa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-6c0b88068c143f15.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-7f8d7fcdf058a845.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-22163556cd38bc88.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-141436fd26dd56fc.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/e81df11490b4413b.css +0 -1
- /package/apps/pwa/out/_next/static/{MObU8ujkMciAKr6ljAV05 → rfkMm4movqkqMebBrCXiR}/_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,7 +19,7 @@ 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';
|
|
21
24
|
import { ToolCallTiming } from './chat/tool-call-timing.js';
|
|
22
25
|
import {
|
|
@@ -37,8 +40,9 @@ import {
|
|
|
37
40
|
type ProviderFallbackTerminalVerdict,
|
|
38
41
|
} from './session-runtime/retry-policy.js';
|
|
39
42
|
import { fetchApiWithRetry, OverloadFailoverError, type FetchApiWithRetryOpts } from './session-runtime/retry-api.js';
|
|
43
|
+
import { BedrockProvider, isBedrockCompatibleModel, makeBedrockProvider } from './llm/bedrock-provider.js';
|
|
40
44
|
import { resolveModelAlias } from './intelligence-map/model-alias.js';
|
|
41
|
-
import { reasoningEffortCeiling as reasoningEffortCeilingOf } from './intelligence-map/model-catalog.js';
|
|
45
|
+
import { BUILTIN_CATALOG, reasoningEffortCeiling as reasoningEffortCeilingOf } from './intelligence-map/model-catalog.js';
|
|
42
46
|
import { inferProviderFromModel as registryInferProviderFromModel } from './registry/normalize.js';
|
|
43
47
|
import { closestMatches } from './tool-name-suggest.js';
|
|
44
48
|
import { undoTurnRuntime } from './tool-runtime/undo-turn-runtime.js';
|
|
@@ -86,6 +90,8 @@ export type ToolResultContentItem =
|
|
|
86
90
|
* - `reasoningDetails`: OpenRouter `reasoning_details[]` — 2026-09-23 · Kimi K3·GLM 은 도구 루프에서 이전 추론을
|
|
87
91
|
* 되돌려 받아야 한다(Kimi 공식 문서: 「K3 는 다중 턴·도구 호출 루프에서 필수」 · OpenRouter 가 이 배열로 통일). */
|
|
88
92
|
export interface ProviderToolMeta { thoughtSignature?: string; reasoningDetails?: Array<Record<string, unknown>> }
|
|
93
|
+
/** OR-TOOLARGS-REPAIR — 깨진 도구 인자의 요약(원문은 싣지 않는다 · 길이와 끝난 이유만). */
|
|
94
|
+
export interface ToolArgsInvalid { chars: number; finishReason: string | null }
|
|
89
95
|
|
|
90
96
|
export type ContentBlock =
|
|
91
97
|
| { type: 'text'; text: string }
|
|
@@ -274,6 +280,10 @@ export type LLMStreamEvent =
|
|
|
274
280
|
* ("Function call is missing a thought_signature"). Other
|
|
275
281
|
* providers ignore this field. */
|
|
276
282
|
providerMeta?: ProviderToolMeta;
|
|
283
|
+
/** OR-TOOLARGS-REPAIR (2026-10-10) — 인자 JSON 이 깨져(잘림·문법 오류) 파싱에 실패했다는 표지.
|
|
284
|
+
* ⛔ OpenRouter 경로(`parseOpenAISSELines` 의 `flagInvalidToolArgs`)에서만 실린다 — 다른 공급자는 종전대로
|
|
285
|
+
* `{}` 로 대체되고 이 칸이 없다. 실리면 `args` 는 `{}` 이고, 도구 루프는 실행하지 않고 오류 결과를 돌려준다. */
|
|
286
|
+
argsInvalid?: ToolArgsInvalid;
|
|
277
287
|
}
|
|
278
288
|
/** Reasoning-summary delta from Codex Responses API (gpt-5 family).
|
|
279
289
|
* `summary_part_added` is a separator marking the boundary between
|
|
@@ -322,6 +332,8 @@ export interface LLMOpts {
|
|
|
322
332
|
temperature?: number;
|
|
323
333
|
maxTokens?: number;
|
|
324
334
|
signal?: AbortSignal;
|
|
335
|
+
/** Override the text-stream idle watchdog per request (milliseconds). */
|
|
336
|
+
streamIdleTimeoutMs?: number;
|
|
325
337
|
/** Optional per-request usage telemetry from the provider stream. */
|
|
326
338
|
onUsage?(usage: LLMUsage): void;
|
|
327
339
|
/** Optional model role attached to this request's usage observation. */
|
|
@@ -370,7 +382,9 @@ export interface LLMOpts {
|
|
|
370
382
|
/** Prompt-caching toggle. Honored by Anthropic (attaches
|
|
371
383
|
* cache_control markers on system + tools + 2nd-to-last history
|
|
372
384
|
* message) and OpenAI (passes stream_options.include_usage so
|
|
373
|
-
* the automatic cache telemetry reaches us).
|
|
385
|
+
* the automatic cache telemetry reaches us). OpenRouter `anthropic/*` ·
|
|
386
|
+
* `moonshotai/*` get part-level cache_control on system (first 2) + last 2
|
|
387
|
+
* messages (`src/prompt-cache/openrouter.ts`). Default `true`.
|
|
374
388
|
* Pass `false` for tests that pin the legacy wire shape. */
|
|
375
389
|
promptCache?: boolean;
|
|
376
390
|
/** Cache TTL tier. `'5m'` (default) is the ephemeral tier; `'1h'`
|
|
@@ -1109,7 +1123,12 @@ function parseHarmonyHeader(header: string): { channel: HarmonyChannel; toolName
|
|
|
1109
1123
|
* unit tests — no fetch dependency. */
|
|
1110
1124
|
export async function* parseOpenAISSELines(
|
|
1111
1125
|
lines: AsyncIterable<string> | Iterable<string>,
|
|
1126
|
+
/** OR-TOOLARGS-REPAIR (2026-10-10) — `flagInvalidToolArgs` 가 참이면(OpenRouter 경로) 인자 JSON 파싱 실패를
|
|
1127
|
+
* `{}` 로 «조용히» 바꾸지 않고 `argsInvalid` 표지를 단다(도구 루프가 실행을 막는다) ⊕ 관측을 남긴다.
|
|
1128
|
+
* ⛔ 생략·거짓이면 종전과 바이트 동일(다른 공급자 무변경). */
|
|
1129
|
+
parseOpts: { flagInvalidToolArgs?: boolean } = {},
|
|
1112
1130
|
): AsyncGenerator<LLMStreamEvent, void, unknown> {
|
|
1131
|
+
const flagInvalidToolArgs = parseOpts.flagInvalidToolArgs === true;
|
|
1113
1132
|
const { parseOpenAIUsage } = await import('./prompt-cache/openai.js');
|
|
1114
1133
|
// Indexed by `tc.index` (OpenAI standard) — partial-chunk streaming
|
|
1115
1134
|
// assembles into a single accumulator per index. Gemini OpenAI-compat
|
|
@@ -1126,10 +1145,25 @@ export async function* parseOpenAISSELines(
|
|
|
1126
1145
|
reasoningDetailsAttached = true;
|
|
1127
1146
|
return [...reasoningDetailsAcc.values()];
|
|
1128
1147
|
};
|
|
1129
|
-
const yieldAccum = (acc: OpenAIToolCallAccum): LLMStreamEvent | null => {
|
|
1148
|
+
const yieldAccum = (acc: OpenAIToolCallAccum, finishReason: string | null): LLMStreamEvent | null => {
|
|
1130
1149
|
if (!acc.name) return null;
|
|
1131
1150
|
let args: Record<string, unknown> = {};
|
|
1132
|
-
|
|
1151
|
+
let argsInvalid: ToolArgsInvalid | undefined;
|
|
1152
|
+
try {
|
|
1153
|
+
args = acc.argsJson ? JSON.parse(acc.argsJson) : {};
|
|
1154
|
+
} catch {
|
|
1155
|
+
// 종전: `{}` 로 대체해 도구가 엉뚱한 기본값으로 돌았다(조용한 실패). OpenRouter 경로만 표지를 단다.
|
|
1156
|
+
if (flagInvalidToolArgs) {
|
|
1157
|
+
argsInvalid = { chars: acc.argsJson.length, finishReason };
|
|
1158
|
+
debug.log('llm.openrouter', 'tool-args-invalid', {
|
|
1159
|
+
tool: acc.name,
|
|
1160
|
+
chars: acc.argsJson.length,
|
|
1161
|
+
finishReason,
|
|
1162
|
+
// 원문은 앞 몇십 자만 · 비밀 가림.
|
|
1163
|
+
head: redactSecretText(acc.argsJson.slice(0, 60)),
|
|
1164
|
+
}, { level: 'warn' });
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1133
1167
|
const reasoningDetails = takeReasoningDetails();
|
|
1134
1168
|
const meta: ProviderToolMeta = {
|
|
1135
1169
|
...(acc.thoughtSignature !== undefined ? { thoughtSignature: acc.thoughtSignature } : {}),
|
|
@@ -1141,6 +1175,7 @@ export async function* parseOpenAISSELines(
|
|
|
1141
1175
|
name: acc.name,
|
|
1142
1176
|
args,
|
|
1143
1177
|
...(Object.keys(meta).length > 0 ? { providerMeta: meta } : {}),
|
|
1178
|
+
...(argsInvalid !== undefined ? { argsInvalid } : {}),
|
|
1144
1179
|
};
|
|
1145
1180
|
};
|
|
1146
1181
|
// Per-stream Harmony filter — routes `<|channel|>final` content to
|
|
@@ -1242,7 +1277,7 @@ export async function* parseOpenAISSELines(
|
|
|
1242
1277
|
// (or omit id on continuation frags), so this only triggers on
|
|
1243
1278
|
// the Gemini complete-frag pattern.
|
|
1244
1279
|
if (accum && tc.id && accum.id && tc.id !== accum.id && accum.argsJson.length > 0) {
|
|
1245
|
-
const ev = yieldAccum(accum);
|
|
1280
|
+
const ev = yieldAccum(accum, null);
|
|
1246
1281
|
if (ev) yield ev;
|
|
1247
1282
|
accum = undefined;
|
|
1248
1283
|
toolCalls.delete(idx);
|
|
@@ -1293,8 +1328,17 @@ export async function* parseOpenAISSELines(
|
|
|
1293
1328
|
(choice.finish_reason === 'tool_calls'
|
|
1294
1329
|
|| (choice.finish_reason && toolCalls.size > 0))
|
|
1295
1330
|
) {
|
|
1331
|
+
// OR-TOOLARGS-REPAIR — 출력 상한에서 잘린 턴(`length`)의 도구 호출은 인자가 온전해 보여도 «잘렸을 수 있다».
|
|
1332
|
+
// 관측만 남긴다(파싱 실패면 yieldAccum 이 `argsInvalid` 로 막는다). 상한 조정은 범위 밖.
|
|
1333
|
+
if (flagInvalidToolArgs && choice.finish_reason === 'length' && toolCalls.size > 0) {
|
|
1334
|
+
debug.log('llm.openrouter', 'tool-args-maybe-truncated', {
|
|
1335
|
+
finishReason: 'length',
|
|
1336
|
+
tools: [...toolCalls.values()].map((tc) => tc.name),
|
|
1337
|
+
chars: [...toolCalls.values()].map((tc) => tc.argsJson.length),
|
|
1338
|
+
}, { level: 'warn' });
|
|
1339
|
+
}
|
|
1296
1340
|
for (const [, tc] of toolCalls) {
|
|
1297
|
-
const ev = yieldAccum(tc);
|
|
1341
|
+
const ev = yieldAccum(tc, typeof choice.finish_reason === 'string' ? choice.finish_reason : null);
|
|
1298
1342
|
if (ev) yield ev;
|
|
1299
1343
|
}
|
|
1300
1344
|
toolCalls.clear();
|
|
@@ -1329,6 +1373,7 @@ function retryOptsFor(
|
|
|
1329
1373
|
}
|
|
1330
1374
|
|
|
1331
1375
|
function inferOpenAIProviderName(url: string): string {
|
|
1376
|
+
if (/^https?:\/\/openrouter\.ai(?::\d+)?(?:\/|$)/i.test(url)) return 'openrouter';
|
|
1332
1377
|
if (url.includes('x.ai')) return 'grok';
|
|
1333
1378
|
if (url.includes('openai.com')) return 'openai';
|
|
1334
1379
|
if (url.includes('localhost') || url.includes('127.0.0.1')) return 'local';
|
|
@@ -1383,7 +1428,9 @@ async function* streamOpenAIEvents(
|
|
|
1383
1428
|
let textChars = 0;
|
|
1384
1429
|
let toolCalls = 0;
|
|
1385
1430
|
try {
|
|
1386
|
-
|
|
1431
|
+
// OR-TOOLARGS-REPAIR — 깨진 도구 인자 표지는 OpenRouter 엔드포인트에서만 켠다(다른 공급자 무변경).
|
|
1432
|
+
const flagInvalidToolArgs = inferOpenAIProviderName(url) === 'openrouter';
|
|
1433
|
+
for await (const ev of parseOpenAISSELines(sseLineStream(response.body!), flagInvalidToolArgs ? { flagInvalidToolArgs } : {})) {
|
|
1387
1434
|
if (ev.type === 'text') textChars += ev.delta.length;
|
|
1388
1435
|
else if (ev.type === 'tool_call') toolCalls++;
|
|
1389
1436
|
yield ev;
|
|
@@ -1746,7 +1793,7 @@ export const REASONING_CYCLE: readonly import('./user-config.js').ReasoningLevel
|
|
|
1746
1793
|
|
|
1747
1794
|
/** Does the (provider, model) pair support a "think before answering"
|
|
1748
1795
|
* reasoning surface? Capability-based: gpt-5 family on Codex /
|
|
1749
|
-
* Responses API + Anthropic
|
|
1796
|
+
* Responses API + Anthropic Claude 3.7+ (extended thinking)
|
|
1750
1797
|
* + OpenAI o-series. Other providers / older models return false so
|
|
1751
1798
|
* the HUD pill auto-hides and the wire body skips the reasoning
|
|
1752
1799
|
* field — no user toggle required. */
|
|
@@ -1768,9 +1815,7 @@ export function modelSupportsReasoning(
|
|
|
1768
1815
|
return m.startsWith('o1') || m.startsWith('o3') || m.startsWith('o4');
|
|
1769
1816
|
}
|
|
1770
1817
|
if (provider === 'anthropic') {
|
|
1771
|
-
|
|
1772
|
-
// (opus-4, sonnet-4, haiku-4) plus the 3.7 line.
|
|
1773
|
-
return m.includes('-4-') || m.includes('-3-7') || m.includes('3.7') || m.includes('claude-4');
|
|
1818
|
+
return claudeSupportsThinking(model);
|
|
1774
1819
|
}
|
|
1775
1820
|
if (provider === 'gemini') {
|
|
1776
1821
|
// Gemini 2.5+ family supports thinking budget (thinkingConfig).
|
|
@@ -1926,16 +1971,32 @@ function mapReasoningLevelToAnthropicEffort(
|
|
|
1926
1971
|
* 🩹 그래서 규칙을 이름 목록이 아니라 «수»로 둔다 — 목록은 새 모델마다 늙지만 세대 비교는 안 늙는다.
|
|
1927
1972
|
* ⚠️ 알 수 없는 형태는 legacy 로 둔다(무회귀). 판정 못 하면 종전 동작이 정답이다. */
|
|
1928
1973
|
function usesAdaptiveThinking(model: string | undefined): boolean {
|
|
1974
|
+
const version = claudeVersion(model, true);
|
|
1975
|
+
if (!version) return false;
|
|
1976
|
+
if (version.generation >= 5) return true;
|
|
1977
|
+
return version.generation === 4 && version.minor >= 7;
|
|
1978
|
+
}
|
|
1979
|
+
|
|
1980
|
+
/** Shared numeric version parser for adaptive API shape and extended-thinking support. */
|
|
1981
|
+
function claudeVersion(model: string | undefined, requireTerminal = false): { generation: number; minor: number } | undefined {
|
|
1929
1982
|
// 끝에 붙는 릴리스 날짜(`-20251101`)는 버전이 아니다 — 떼고 본다.
|
|
1930
1983
|
const m = (model ?? '').toLowerCase().replace(/-\d{8}$/, '');
|
|
1931
|
-
const v
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
return generation === 4 && minor >= 7;
|
|
1984
|
+
for (const v of m.matchAll(/-(\d+)(?:[-.](\d+))?(?=-|$)/g)) {
|
|
1985
|
+
if (requireTerminal && v.index + v[0].length !== m.length) continue;
|
|
1986
|
+
return { generation: Number(v[1]), minor: v[2] === undefined ? 0 : Number(v[2]) };
|
|
1987
|
+
}
|
|
1988
|
+
return undefined;
|
|
1937
1989
|
}
|
|
1938
1990
|
|
|
1991
|
+
function claudeSupportsThinking(model: string | undefined): boolean {
|
|
1992
|
+
// includes, not startsWith: prefixed ids (`us.anthropic.claude-…`, `anthropic/claude-…`) passed the old substring check.
|
|
1993
|
+
if (!model?.toLowerCase().includes('claude-')) return false;
|
|
1994
|
+
const version = claudeVersion(model);
|
|
1995
|
+
return version !== undefined && (version.generation > 3 || version.generation === 3 && version.minor >= 7);
|
|
1996
|
+
}
|
|
1997
|
+
|
|
1998
|
+
export const _claudeSupportsThinkingForContractTest = claudeSupportsThinking;
|
|
1999
|
+
|
|
1939
2000
|
/** ⛔ 테스트 전용 노출이 아니다 — 모델 계열 계약은 «이름을 가진 판정»이라 회귀를 테스트로 물어야 한다.
|
|
1940
2001
|
* 이 파일 안 두 조립부(:3102·:9591)가 그 값을 쓰고, 그 계약이 틀리면 provider 가 통째로 막힌다. */
|
|
1941
2002
|
export const _usesAdaptiveThinkingForContractTest = usesAdaptiveThinking;
|
|
@@ -2406,12 +2467,29 @@ export function dedupeToolsByName(tools: LLMToolSpec[] | undefined): LLMToolSpec
|
|
|
2406
2467
|
return out.length === tools.length ? tools : out;
|
|
2407
2468
|
}
|
|
2408
2469
|
|
|
2409
|
-
|
|
2470
|
+
/** OpenRouter's Moonshot/Kimi tool schema accepts a bare $ref and single-schema items. */
|
|
2471
|
+
export function sanitizeToolSchemaForKimi(schema: unknown): unknown {
|
|
2472
|
+
if (Array.isArray(schema)) return schema.map(sanitizeToolSchemaForKimi);
|
|
2473
|
+
if (!schema || typeof schema !== 'object') return schema;
|
|
2474
|
+
const record = schema as Record<string, unknown>;
|
|
2475
|
+
if ('$ref' in record) return { $ref: record.$ref };
|
|
2476
|
+
return Object.fromEntries(Object.entries(record).map(([key, value]) => [
|
|
2477
|
+
key,
|
|
2478
|
+
sanitizeToolSchemaForKimi(key === 'items' && Array.isArray(value) ? value[0] : value),
|
|
2479
|
+
]));
|
|
2480
|
+
}
|
|
2481
|
+
|
|
2482
|
+
export function toOpenAITools(tools: LLMToolSpec[] | undefined, kimi = false): any[] | undefined {
|
|
2410
2483
|
const unique = dedupeToolsByName(tools);
|
|
2411
2484
|
if (!unique || unique.length === 0) return undefined;
|
|
2412
2485
|
return unique.map(t => ({
|
|
2413
2486
|
type: 'function',
|
|
2414
|
-
function: {
|
|
2487
|
+
function: {
|
|
2488
|
+
name: t.name, description: t.description,
|
|
2489
|
+
parameters: kimi
|
|
2490
|
+
? sanitizeToolSchemaForKimi(strictifyToolSchema(t.parameters))
|
|
2491
|
+
: strictifyToolSchema(t.parameters),
|
|
2492
|
+
},
|
|
2415
2493
|
}));
|
|
2416
2494
|
}
|
|
2417
2495
|
|
|
@@ -3134,13 +3212,9 @@ async function* streamAnthropicEvents(
|
|
|
3134
3212
|
// forcing a single thinking block before all tools). Improves
|
|
3135
3213
|
// multi-tool turn quality — the model can decide what to call
|
|
3136
3214
|
// next based on the prior tool's output thinking. Only supported
|
|
3137
|
-
// on extended-thinking-capable models (
|
|
3138
|
-
const model: string = (body?.model ?? '') as string;
|
|
3139
|
-
const m = model.toLowerCase();
|
|
3140
|
-
const supportsThinking =
|
|
3141
|
-
m.includes('-4-') || m.includes('-3-7') || m.includes('3.7') || m.includes('claude-4');
|
|
3215
|
+
// on extended-thinking-capable models (Claude 3.7+).
|
|
3142
3216
|
const betas: string[] = ['fine-grained-tool-streaming-2025-05-14'];
|
|
3143
|
-
if (
|
|
3217
|
+
if (claudeSupportsThinking(body?.model)) betas.push('interleaved-thinking-2025-05-14');
|
|
3144
3218
|
|
|
3145
3219
|
const response = await fetchApiWithRetry(
|
|
3146
3220
|
ANTHROPIC_API_URL,
|
|
@@ -3894,6 +3968,7 @@ export const PROVIDERS: Record<string, LLMProvider> = {
|
|
|
3894
3968
|
streamChat: (messages, opts = {}) => makeOpenRouterProvider({ provider: 'openrouter' }).streamChat!(messages, opts),
|
|
3895
3969
|
chat: (messages, opts = {}) => makeOpenRouterProvider({ provider: 'openrouter' }).chat!(messages, opts),
|
|
3896
3970
|
},
|
|
3971
|
+
bedrock: BedrockProvider, // 명시 선택 전용 — 자동 순서·폴백 체인에 «안» 넣는다(src/llm/bedrock-provider.ts)
|
|
3897
3972
|
};
|
|
3898
3973
|
|
|
3899
3974
|
const AUTOMATIC_PROVIDER_ORDER = ['grok', 'anthropic', 'gemini', 'local'] as const;
|
|
@@ -4075,12 +4150,13 @@ export function decideProviderForConfig(
|
|
|
4075
4150
|
return { provider, model: selectedModel, auth: baseUrl || getLocalLLMUrl() ? 'local' : 'none' };
|
|
4076
4151
|
case 'openrouter':
|
|
4077
4152
|
return { provider, model: selectedModel, auth: apiKey || getOpenRouterApiKey() ? 'apikey' : 'none' };
|
|
4153
|
+
case 'bedrock': return { provider, model: selectedModel, auth: authKindForProvider('bedrock', selectedModel) };
|
|
4078
4154
|
}
|
|
4079
4155
|
throw new Error(`unknown provider: ${provider as string}`);
|
|
4080
4156
|
}
|
|
4081
4157
|
|
|
4082
4158
|
function isKnownProviderName(provider: string): provider is ConcreteProviderName {
|
|
4083
|
-
return provider === 'grok' || provider === 'openai' || provider === 'openai-codex' || provider === 'anthropic' || provider === 'gemini' || provider === 'local' || provider === 'openrouter';
|
|
4159
|
+
return provider === 'grok' || provider === 'openai' || provider === 'openai-codex' || provider === 'anthropic' || provider === 'gemini' || provider === 'local' || provider === 'openrouter' || provider === 'bedrock';
|
|
4084
4160
|
}
|
|
4085
4161
|
|
|
4086
4162
|
function authKindForProvider(provider: string, model: string, apiKey?: string): ProviderDecisionAuth {
|
|
@@ -4095,6 +4171,7 @@ function authKindForProvider(provider: string, model: string, apiKey?: string):
|
|
|
4095
4171
|
if (provider === 'anthropic') return getAnthropicApiKey() ? 'apikey' : 'none';
|
|
4096
4172
|
if (provider === 'gemini') return getGeminiApiKey() ? 'apikey' : 'none';
|
|
4097
4173
|
if (provider === 'openrouter') return getOpenRouterApiKey() ? 'apikey' : 'none';
|
|
4174
|
+
if (provider === 'bedrock') return BedrockProvider.available() ? 'apikey' : 'none';
|
|
4098
4175
|
if (provider === 'openai-codex') {
|
|
4099
4176
|
try {
|
|
4100
4177
|
return codexOAuthAvailable() ? 'oauth' : 'none';
|
|
@@ -4114,6 +4191,7 @@ function defaultModelForProvider(provider: ConcreteProviderName): string {
|
|
|
4114
4191
|
case 'gemini': return GEMINI_MODEL;
|
|
4115
4192
|
case 'local': return LOCAL_LLM_MODEL;
|
|
4116
4193
|
case 'openrouter': return OPENROUTER_MODEL;
|
|
4194
|
+
case 'bedrock': return BedrockProvider.defaultModel;
|
|
4117
4195
|
}
|
|
4118
4196
|
throw new Error(`unknown provider: ${provider as string}`);
|
|
4119
4197
|
}
|
|
@@ -4237,7 +4315,7 @@ export function getProvider(model?: string): LLMProvider {
|
|
|
4237
4315
|
if (adapted && PROVIDERS[adapted]) return PROVIDERS[adapted]!;
|
|
4238
4316
|
// Unknown prefix — look up by exact name match on defaults
|
|
4239
4317
|
for (const p of Object.values(PROVIDERS)) {
|
|
4240
|
-
if (p.defaultModel === resolved) return p;
|
|
4318
|
+
if (p.name !== 'bedrock' && p.defaultModel === resolved) return p; // bedrock 은 명시 선택 전용
|
|
4241
4319
|
}
|
|
4242
4320
|
}
|
|
4243
4321
|
|
|
@@ -4364,6 +4442,7 @@ export function buildMessagesWithContext(
|
|
|
4364
4442
|
|
|
4365
4443
|
// Re-export converters so tests/adapters can assert wire-format correctness.
|
|
4366
4444
|
export { toOpenAIMessage, toOpenAIMessages, toAnthropicMessage, systemToAnthropicString };
|
|
4445
|
+
export { usesAdaptiveThinking, mapReasoningLevelToAnthropicThinking, mapReasoningLevelToAnthropicEffort, sseLineStream, retryOptsFor }; // src/llm/bedrock-provider.ts
|
|
4367
4446
|
|
|
4368
4447
|
/**
|
|
4369
4448
|
* Best-effort classification of whether a model accepts image inputs.
|
|
@@ -4420,7 +4499,10 @@ export function isLikelyVisionModel(model: string | undefined): boolean {
|
|
|
4420
4499
|
* Convenience wrapper — stream chunks via a callback, returning the full text.
|
|
4421
4500
|
* Mirrors the existing `streamGrok()` signature in chat.ts for drop-in use.
|
|
4422
4501
|
*/
|
|
4423
|
-
|
|
4502
|
+
// ⭐ OPENROUTER-OPTIMIZE G9 — `reportedCostUsd`(OpenRouter `usage.cost`)도 싣는다. 빠지면 `stream-llm` 행이
|
|
4503
|
+
// 실청구액을 잃고 카탈로그 추정(대개 `cost.kind=unknown`)으로 떨어진다(리뷰·저작 행 실측).
|
|
4504
|
+
// 합산은 토큰 칸과 같은 규약이다 — OpenAI 호환 스트림은 `usage` 를 마지막 청크에 «한 번» 싣는다(누적 반복 보고 아님).
|
|
4505
|
+
type ObservedUsage = Pick<LLMUsage, 'inputTokens' | 'outputTokens' | 'cacheReadInputTokens' | 'cacheCreationInputTokens' | 'reportedCostUsd'>;
|
|
4424
4506
|
|
|
4425
4507
|
type ProviderTextResult =
|
|
4426
4508
|
| { ok: true; full: string; usage: ObservedUsage | 'unmeasured' }
|
|
@@ -4428,7 +4510,7 @@ type ProviderTextResult =
|
|
|
4428
4510
|
|
|
4429
4511
|
function accumulateUsage(usage: ObservedUsage | undefined, received: LLMUsage): ObservedUsage {
|
|
4430
4512
|
const total = { ...usage };
|
|
4431
|
-
for (const field of ['inputTokens', 'outputTokens', 'cacheReadInputTokens', 'cacheCreationInputTokens'] as const) {
|
|
4513
|
+
for (const field of ['inputTokens', 'outputTokens', 'cacheReadInputTokens', 'cacheCreationInputTokens', 'reportedCostUsd'] as const) {
|
|
4432
4514
|
if (received[field] !== undefined) total[field] = (total[field] ?? 0) + received[field];
|
|
4433
4515
|
}
|
|
4434
4516
|
return total;
|
|
@@ -4458,17 +4540,40 @@ async function consumeProviderText(
|
|
|
4458
4540
|
// Preserve the provider or callback error that caused this close.
|
|
4459
4541
|
}
|
|
4460
4542
|
};
|
|
4543
|
+
const idleMs = opts.streamIdleTimeoutMs ?? (
|
|
4544
|
+
usesLongReasoningIdle(getModelFamily(opts.model ?? provider.defaultModel), provider.name)
|
|
4545
|
+
? STREAM_IDLE_TIMEOUT_MS_REASONING : STREAM_IDLE_TIMEOUT_MS
|
|
4546
|
+
);
|
|
4461
4547
|
|
|
4462
4548
|
while (true) {
|
|
4463
|
-
let
|
|
4549
|
+
let idleTimer: ReturnType<typeof setTimeout> | undefined;
|
|
4550
|
+
let step: { idle: true } | { idle: false; result: IteratorResult<string | LLMStreamEvent> };
|
|
4464
4551
|
try {
|
|
4465
|
-
step = await
|
|
4552
|
+
step = await Promise.race([
|
|
4553
|
+
iterator.next().then((result) => ({ idle: false as const, result })),
|
|
4554
|
+
new Promise<{ idle: true }>((resolve) => {
|
|
4555
|
+
idleTimer = setTimeout(() => resolve({ idle: true }), idleMs);
|
|
4556
|
+
}),
|
|
4557
|
+
]);
|
|
4466
4558
|
} catch (error) {
|
|
4467
4559
|
await closeIterator();
|
|
4468
4560
|
return { ok: false, full, error };
|
|
4561
|
+
} finally {
|
|
4562
|
+
if (idleTimer !== undefined) clearTimeout(idleTimer);
|
|
4563
|
+
}
|
|
4564
|
+
if (step.idle) {
|
|
4565
|
+
debug.log('llm', 'stream-idle-timeout', {
|
|
4566
|
+
provider: provider.name, model: opts.model ?? provider.defaultModel,
|
|
4567
|
+
idleMs, receivedChars: full.length, site: 'stream-llm',
|
|
4568
|
+
});
|
|
4569
|
+
const error = new Error(`stream idle timeout after ${idleMs}ms`);
|
|
4570
|
+
error.name = 'StreamIdleTimeoutError';
|
|
4571
|
+
// An async generator can leave return() pending behind a stalled next().
|
|
4572
|
+
void closeIterator();
|
|
4573
|
+
return { ok: false, full, error };
|
|
4469
4574
|
}
|
|
4470
|
-
if (step.done) return { ok: true, full, usage: usage ?? 'unmeasured' };
|
|
4471
|
-
const event = typeof step.value === 'string' ? { type: 'text' as const, delta: step.value } : step.value;
|
|
4575
|
+
if (step.result.done) return { ok: true, full, usage: usage ?? 'unmeasured' };
|
|
4576
|
+
const event = typeof step.result.value === 'string' ? { type: 'text' as const, delta: step.result.value } : step.result.value;
|
|
4472
4577
|
if (event.type === 'usage') {
|
|
4473
4578
|
usage = accumulateUsage(usage, event.usage);
|
|
4474
4579
|
try {
|
|
@@ -4494,11 +4599,11 @@ export async function streamLLM(
|
|
|
4494
4599
|
onChunk: (delta: string, full: string) => void,
|
|
4495
4600
|
opts: LLMOpts & { provider?: LLMProvider; initialProvider?: LLMProvider; onResolvedProvider?: (provider: string, model: string) => void } = {},
|
|
4496
4601
|
): Promise<string> {
|
|
4602
|
+
const started = Date.now();
|
|
4497
4603
|
let activeProvider = opts.provider ?? opts.initialProvider ?? resolveDefaultProvider(opts.model);
|
|
4498
4604
|
const attemptedProviders = new Set<string>([activeProvider.name]);
|
|
4499
4605
|
let blockedProviders: ProviderFallbackAttempt[] = [];
|
|
4500
4606
|
let modelOverride = opts.model;
|
|
4501
|
-
const started = Date.now();
|
|
4502
4607
|
|
|
4503
4608
|
while (true) {
|
|
4504
4609
|
const finalized = finalizeStreamingProviderModel(
|
|
@@ -4517,6 +4622,7 @@ export async function streamLLM(
|
|
|
4517
4622
|
maxTokens: opts.maxTokens,
|
|
4518
4623
|
temperature: opts.temperature,
|
|
4519
4624
|
}, { level: 'info' });
|
|
4625
|
+
// Keep text-only stream failures on streamLLM's existing provider fallback path.
|
|
4520
4626
|
const consumed = await consumeProviderText(
|
|
4521
4627
|
activeProvider,
|
|
4522
4628
|
messages,
|
|
@@ -4534,6 +4640,7 @@ export async function streamLLM(
|
|
|
4534
4640
|
logAgentTurnUsage(activeModel, consumed.usage, { providerName: activeProvider.name, site: 'stream-llm', role: opts.usageRole });
|
|
4535
4641
|
} catch { /* best-effort observation */ }
|
|
4536
4642
|
}
|
|
4643
|
+
debug.log('llm', 'outcome', { provider: activeProvider.name, status: 'ok', kind: 'streamLLM', durationMs: Date.now() - started });
|
|
4537
4644
|
debug.log('llm.router.done', 'streamLLM', {
|
|
4538
4645
|
provider: activeProvider.name,
|
|
4539
4646
|
model: activeModel,
|
|
@@ -4569,7 +4676,10 @@ export async function streamLLM(
|
|
|
4569
4676
|
message: reason,
|
|
4570
4677
|
...(isAuthRejectionError(err) ? { authRejected: true } : {}),
|
|
4571
4678
|
}, { level: 'error' });
|
|
4572
|
-
if (opts.provider)
|
|
4679
|
+
if (opts.provider) {
|
|
4680
|
+
debug.log('llm', 'outcome', { provider: activeProvider.name, status: 'error', kind: 'streamLLM', durationMs: Date.now() - started });
|
|
4681
|
+
throw err;
|
|
4682
|
+
}
|
|
4573
4683
|
const remaining = remainingFallbackProviderNames(attemptedProviders, opts);
|
|
4574
4684
|
const verdict = decideProviderFallback({
|
|
4575
4685
|
err,
|
|
@@ -4594,6 +4704,7 @@ export async function streamLLM(
|
|
|
4594
4704
|
continue;
|
|
4595
4705
|
}
|
|
4596
4706
|
if (verdict.action === 'stop') {
|
|
4707
|
+
debug.log('llm', 'outcome', { provider: activeProvider.name, status: 'error', kind: 'streamLLM', durationMs: Date.now() - started });
|
|
4597
4708
|
debug.log('llm.router', 'provider-fallback-stop', {
|
|
4598
4709
|
blockedProviders,
|
|
4599
4710
|
category: verdict.category,
|
|
@@ -4612,6 +4723,7 @@ export async function streamLLM(
|
|
|
4612
4723
|
...(fallback ? { skippedFallbackProvider: fallback.name, emittedChars: full.length } : {}),
|
|
4613
4724
|
}, { level: 'error' });
|
|
4614
4725
|
onChunk(finalDelta, finalText);
|
|
4726
|
+
debug.log('llm', 'outcome', { provider: activeProvider.name, status: 'fallback-exhausted', kind: 'streamLLM', durationMs: Date.now() - started });
|
|
4615
4727
|
return finalText;
|
|
4616
4728
|
}
|
|
4617
4729
|
}
|
|
@@ -5009,6 +5121,15 @@ const LOCAL_TOOL_DISCIPLINE = [
|
|
|
5009
5121
|
'- 범위 읽기만으로 판단할 수 없을 때에만 전체 읽기를 선택하고, 읽은 뒤에는 다음 행동을 계속 결정하라.',
|
|
5010
5122
|
].join('\n');
|
|
5011
5123
|
|
|
5124
|
+
/** OpenRouter(`openrouter/…`) GLM·Kimi·Qwen 전용 도구 호출 규율 — 다른 군 상수와 합성하지 않는 독립 상수. */
|
|
5125
|
+
export const OPEN_WEIGHT_TOOL_DISCIPLINE = [
|
|
5126
|
+
'[open-weight tool-use discipline]',
|
|
5127
|
+
'- 도구로 할 수 있는 일은 이번 응답에서 바로 도구를 호출하라. "먼저 읽겠다" 또는 "확인하겠다" 같은 계획만 말하고 응답을 끝내지 마라.',
|
|
5128
|
+
'- 작업을 시작하는 첫 응답에는 도구 호출이 하나 이상 있어야 한다.',
|
|
5129
|
+
'- 도구 호출 인자는 해당 도구의 스키마에 맞는 JSON 으로 내라.',
|
|
5130
|
+
'- 충분한 근거가 모이면 도구 호출 없이 최종 답을 평문으로 써서 끝내라.',
|
|
5131
|
+
].join('\n');
|
|
5132
|
+
|
|
5012
5133
|
/** 모델군 → 그 군에 주입할 툴 규율(없으면 `null`). **능력 술어 판** — 2026-08-14.
|
|
5013
5134
|
*
|
|
5014
5135
|
* ⛔ **왜 `if` 세 개가 아니라 이 표인가**: codex·grok·local 이 각각 「같은 모양의 if」로 붙어 있었고,
|
|
@@ -5030,6 +5151,7 @@ const TOOL_DISCIPLINE_BY_FAMILY: Record<ModelFamily, string | null> = {
|
|
|
5030
5151
|
codex: CODEX_TOOL_DISCIPLINE,
|
|
5031
5152
|
grok: GROK_TOOL_DISCIPLINE,
|
|
5032
5153
|
local: LOCAL_TOOL_DISCIPLINE,
|
|
5154
|
+
'open-weight': OPEN_WEIGHT_TOOL_DISCIPLINE,
|
|
5033
5155
|
// ⬇ 아래 넷은 「아직 안 쟀다」이지 「필요 없다」가 아니다.
|
|
5034
5156
|
// `other` 가 0인 것은 ***아무도 other 를 안 쟀기 때문***이고, 실제 자식 하나가 오늘 `other` 였다(`[S]` 실측).
|
|
5035
5157
|
claude: null,
|
|
@@ -5207,6 +5329,19 @@ function appendFinalSynthesisNotice(existingText: string, notice: string): strin
|
|
|
5207
5329
|
return existingText.length > 0 ? `${existingText}\n\n${notice}` : notice;
|
|
5208
5330
|
}
|
|
5209
5331
|
|
|
5332
|
+
export function buildNoFinalSynthesisLead(
|
|
5333
|
+
reason: 'empty-turn' | 'budget-exhausted',
|
|
5334
|
+
toolCallCount: number,
|
|
5335
|
+
locale?: Locale,
|
|
5336
|
+
): string {
|
|
5337
|
+
if (reason === 'empty-turn') {
|
|
5338
|
+
return (locale ?? detectLocale()) === 'ko'
|
|
5339
|
+
? '답을 끝까지 쓰지 못했습니다 — 빈 응답이 이어졌습니다. 질문을 좁혀 다시 물어 주세요(예: 무엇 하나만).'
|
|
5340
|
+
: 'I could not finish the answer — repeated empty responses stopped the reply. Please ask a narrower question (for example, just one thing).';
|
|
5341
|
+
}
|
|
5342
|
+
return format(getMessages(locale).chatNoSynthesisLead ?? getMessages('en').chatNoSynthesisLead!, { n: toolCallCount });
|
|
5343
|
+
}
|
|
5344
|
+
|
|
5210
5345
|
function buildNoFinalSynthesisNotice(reason: 'empty-turn' | 'budget-exhausted'): string {
|
|
5211
5346
|
const why = reason === 'empty-turn'
|
|
5212
5347
|
? 'The model stopped after repeated empty turns.'
|
|
@@ -7734,6 +7869,7 @@ export function selectIntentClassificationMessages(messages: readonly LLMMessage
|
|
|
7734
7869
|
message.content === CODEX_TOOL_DISCIPLINE
|
|
7735
7870
|
|| message.content === GROK_TOOL_DISCIPLINE
|
|
7736
7871
|
|| message.content === LOCAL_TOOL_DISCIPLINE
|
|
7872
|
+
|| message.content === OPEN_WEIGHT_TOOL_DISCIPLINE
|
|
7737
7873
|
)
|
|
7738
7874
|
));
|
|
7739
7875
|
}
|
|
@@ -7946,12 +8082,13 @@ export async function streamLLMWithTools(
|
|
|
7946
8082
|
// the caller — no per-turn duplication when the caller persists new messages.
|
|
7947
8083
|
// Adapters fold multiple system messages, so this composes with (does not
|
|
7948
8084
|
// mutate) the caller's persona/system prompt.
|
|
7949
|
-
// ⭐
|
|
8085
|
+
// ⭐ 각 모델군의 규율은 같은 해소 지점에서 선택한다.
|
|
7950
8086
|
// 대표 2026-08-14: *"claude 제외 다른 LLM 들이 공용화가 많아 보이고, 오히려 claude 일 때
|
|
7951
8087
|
// 옵션화를 해야 하는 게 아닌지"* ⊕ `[S]` 와 합의한 축 분담(축② = 능력 술어는 `[T]` 소유).
|
|
7952
|
-
// ⛔
|
|
8088
|
+
// ⛔ 기존 군의 문면은 «바이트 하나» 안 바뀐다(테스트가 전송분으로 문다).
|
|
7953
8089
|
const toolDiscipline = resolveToolDiscipline(modelFamily);
|
|
7954
8090
|
if (toolDiscipline !== null) {
|
|
8091
|
+
debug.log('llm.tool-discipline', 'injected', { modelFamily, model: effectiveModel, chars: toolDiscipline.length });
|
|
7955
8092
|
// ⛔ **상수를 «그대로» 싣는다 — 합성하지 마라.**
|
|
7956
8093
|
// `selectIntentClassificationMessages` 가 «정확 일치»로 이 메시지를 걸러 내므로,
|
|
7957
8094
|
// 여기서 한 글자라도 덧붙이면 ***분류기 셋이 다시 «오염»된다***(그 함수 주석에 실측이 있다).
|
|
@@ -8295,6 +8432,7 @@ export async function streamLLMWithTools(
|
|
|
8295
8432
|
name: string;
|
|
8296
8433
|
args: Record<string, unknown>;
|
|
8297
8434
|
providerMeta?: ProviderToolMeta;
|
|
8435
|
+
argsInvalid?: ToolArgsInvalid;
|
|
8298
8436
|
}> = [];
|
|
8299
8437
|
const turnStartedAt = Date.now();
|
|
8300
8438
|
debug.log('llm.router', 'tool-loop.turn.start', {
|
|
@@ -8510,6 +8648,7 @@ export async function streamLLMWithTools(
|
|
|
8510
8648
|
name: ev.name,
|
|
8511
8649
|
args: ev.args,
|
|
8512
8650
|
...(ev.providerMeta !== undefined ? { providerMeta: ev.providerMeta } : {}),
|
|
8651
|
+
...(ev.argsInvalid !== undefined ? { argsInvalid: ev.argsInvalid } : {}),
|
|
8513
8652
|
});
|
|
8514
8653
|
} else if (ev.type === 'reasoning') {
|
|
8515
8654
|
// Forward to the optional reasoning handler. Codex Responses
|
|
@@ -8650,11 +8789,12 @@ export async function streamLLMWithTools(
|
|
|
8650
8789
|
if (pendingCalls.length === 0 && turnText.length === 0) {
|
|
8651
8790
|
if (emptyRetries >= MAX_EMPTY_RETRIES) {
|
|
8652
8791
|
const notice = buildNoFinalSynthesisNotice('empty-turn');
|
|
8653
|
-
const
|
|
8792
|
+
const visibleText = finalizeVisibleAssistantText(
|
|
8654
8793
|
appendFinalSynthesisNotice(fullText, notice),
|
|
8655
8794
|
notice,
|
|
8656
8795
|
sawToolRound,
|
|
8657
8796
|
);
|
|
8797
|
+
const finalText = `${buildNoFinalSynthesisLead('empty-turn', toolCallHistory.length)}\n\n${visibleText}`;
|
|
8658
8798
|
handlers.onText('', finalText);
|
|
8659
8799
|
debug.log('llm.router', 'tool-loop.empty-turn.give-up', {
|
|
8660
8800
|
turn, emptyRetries, finalTextInjected: true,
|
|
@@ -9548,6 +9688,22 @@ export async function streamLLMWithTools(
|
|
|
9548
9688
|
return { result: stub, isError: true, phaseRejected: false };
|
|
9549
9689
|
}
|
|
9550
9690
|
}
|
|
9691
|
+
// OR-TOOLARGS-REPAIR (2026-10-10) — 인자 JSON 이 깨진 호출(OpenRouter 경로만 표지가 붙는다)은
|
|
9692
|
+
// ⛔ 실행하지 않는다. 종전엔 `{}` 로 실행돼 도구가 기본값으로 돌고 모델은 «성공»을 받았다.
|
|
9693
|
+
// 기존 dispatch 오류 결과 모양(`{ error }` ⊕ isError)으로 돌려 모델이 다시 부르게 한다.
|
|
9694
|
+
if (call.argsInvalid !== undefined) {
|
|
9695
|
+
debug.log('llm.router', 'tool-loop.tool-args-invalid.blocked', {
|
|
9696
|
+
turn,
|
|
9697
|
+
tool: call.name,
|
|
9698
|
+
chars: call.argsInvalid.chars,
|
|
9699
|
+
finishReason: call.argsInvalid.finishReason,
|
|
9700
|
+
}, { level: 'warn' });
|
|
9701
|
+
return {
|
|
9702
|
+
result: { error: buildInvalidToolArgsMessage(call.argsInvalid) },
|
|
9703
|
+
isError: true,
|
|
9704
|
+
phaseRejected: false,
|
|
9705
|
+
};
|
|
9706
|
+
}
|
|
9551
9707
|
// Codex-family same-args dedup guard (fix L-2). Scope is
|
|
9552
9708
|
// EXPLORATORY_TOOLS only — repeating Bash/RunShell/Edit/Write
|
|
9553
9709
|
// is often legitimate (retry after a fix, apply-then-verify,
|
|
@@ -10629,11 +10785,14 @@ export async function streamLLMWithTools(
|
|
|
10629
10785
|
});
|
|
10630
10786
|
}
|
|
10631
10787
|
const emittedText = synthesizedText ?? noticeWithFallback;
|
|
10632
|
-
const
|
|
10788
|
+
const visibleText = finalizeVisibleAssistantText(
|
|
10633
10789
|
appendFinalSynthesisNotice(fullText, emittedText),
|
|
10634
10790
|
emittedText,
|
|
10635
10791
|
loopTermination === 'aborted' ? false : sawToolRound,
|
|
10636
10792
|
);
|
|
10793
|
+
const finalText = loopTermination === 'budget-exhausted' && synthesizedText === null
|
|
10794
|
+
? `${buildNoFinalSynthesisLead(loopTermination, toolCallHistory.length)}\n\n${visibleText}`
|
|
10795
|
+
: visibleText;
|
|
10637
10796
|
// Skip post-emit when synthesis was already streamed live AND
|
|
10638
10797
|
// finalText matches synthesizedText. Emit when synthesis failed
|
|
10639
10798
|
// (fallback notice) OR finalization enriched the text.
|
|
@@ -10778,13 +10937,21 @@ function makeOpenAICompatProvider(
|
|
|
10778
10937
|
if (!apiKey && !grokSub) {
|
|
10779
10938
|
throw new Error(`${name} unavailable: configure apiKey via \`elanous setup\``);
|
|
10780
10939
|
}
|
|
10781
|
-
const
|
|
10940
|
+
const activeModel = opts.model || model;
|
|
10941
|
+
const tools = toOpenAITools(opts.tools, name === 'openrouter' && openRouterWireModel(activeModel).startsWith('moonshotai/'));
|
|
10942
|
+
// OR-TOOLCHOICE-PASS (2026-10-10) — OpenRouter 경로만 호출자 toolChoice 를 싣는다.
|
|
10943
|
+
// ⛔ grok/openai 호환 경로는 손대지 않는다(무회귀). toolChoice 가 없거나 tools 가 없으면 키 자체를 안 싣는다.
|
|
10944
|
+
const toolChoice = name === 'openrouter' && tools
|
|
10945
|
+
? openRouterToolChoice(openRouterWireModel(activeModel), opts.toolChoice)
|
|
10946
|
+
: undefined;
|
|
10947
|
+
if (toolChoice !== undefined) {
|
|
10948
|
+
debug.log('llm.openrouter', 'tool-choice-sent', { model: openRouterWireModel(activeModel), requested: opts.toolChoice, toolChoice });
|
|
10949
|
+
}
|
|
10782
10950
|
// Image-pipeline P3.5 — gate the synthetic follow-up workaround
|
|
10783
10951
|
// on the userMessage axis for the active model + brand. `name`
|
|
10784
10952
|
// is 'grok' or 'openai' for makeOpenAICompatProvider callers.
|
|
10785
10953
|
// P-3 §6.9 (2026-05-07) — same lookup also gates user-message
|
|
10786
10954
|
// image blocks in the wire.
|
|
10787
|
-
const activeModel = opts.model || model;
|
|
10788
10955
|
const brand = name as Parameters<typeof isVisionCapableModel>[0];
|
|
10789
10956
|
const followup = isVisionCapableModel(brand, activeModel, 'userMessage');
|
|
10790
10957
|
// 구독이 있으면 «엔드포인트와 자격이 통째로» 바뀐다(cli-chat-proxy + Bearer).
|
|
@@ -10796,16 +10963,41 @@ function makeOpenAICompatProvider(
|
|
|
10796
10963
|
if (useSub) {
|
|
10797
10964
|
debug.log('llm.grok', 'credential', { kind: useSub.kind, source: useSub.source, baseUrl: useSub.baseUrl, via: 'compat-provider' });
|
|
10798
10965
|
}
|
|
10966
|
+
let wireMessages = messages.flatMap((m) => toOpenAIMessages(m, {
|
|
10967
|
+
acceptToolImagesViaFollowup: followup,
|
|
10968
|
+
acceptUserMessageImages: followup,
|
|
10969
|
+
...(name === 'openrouter' ? { echoReasoningDetails: true } : {}),
|
|
10970
|
+
}));
|
|
10971
|
+
// OR-ANTHROPIC-CACHE (2026-10-10) — OpenRouter 뒤 anthropic/* · moonshotai/* 만 cache_control 중단점을 싣는다.
|
|
10972
|
+
// ⛔ 다른 OpenRouter 모델과 grok/openai/local 호환 경로는 이 분기를 안 탄다 — 본문 바이트 동일(무회귀).
|
|
10973
|
+
const cacheFamily = name === 'openrouter' ? openRouterPromptCacheFamily(openRouterWireModel(activeModel)) : null;
|
|
10974
|
+
if (cacheFamily) {
|
|
10975
|
+
if (opts.promptCache === false) {
|
|
10976
|
+
debug.log('llm.openrouter', 'prompt-cache', { model: openRouterWireModel(activeModel), applied: false, reason: 'promptCache:false' });
|
|
10977
|
+
} else {
|
|
10978
|
+
const { getDefaultCacheTTL } = await import('./config.js');
|
|
10979
|
+
const ttl = opts.promptCacheTTL ?? getDefaultCacheTTL();
|
|
10980
|
+
const plan = applyOpenRouterCacheControl(wireMessages, { family: cacheFamily, ttl });
|
|
10981
|
+
wireMessages = plan.messages;
|
|
10982
|
+
debug.log('llm.openrouter', 'prompt-cache', {
|
|
10983
|
+
model: openRouterWireModel(activeModel), applied: plan.breakpoints > 0, family: cacheFamily,
|
|
10984
|
+
ttl: cacheFamily === 'anthropic' ? ttl : '5m',
|
|
10985
|
+
breakpoints: plan.breakpoints, system: plan.systemBreakpoints, tail: plan.tailBreakpoints,
|
|
10986
|
+
});
|
|
10987
|
+
}
|
|
10988
|
+
}
|
|
10989
|
+
// OR-STICKY-ROUTING (2026-10-10) — 같은 세션/런의 요청을 같은 상류로 고정해 캐시 적중을 지킨다.
|
|
10990
|
+
// ⛔ openrouter 만, 그리고 키가 있을 때만 싣는다 — 키가 없거나 다른 provider 면 본문·헤더 바이트 동일(무회귀).
|
|
10991
|
+
const sticky = name === 'openrouter' ? openRouterStickySessionKey(opts.sessionId, process.env.ELANOUS_RUN_ID) : null;
|
|
10992
|
+
if (sticky) {
|
|
10993
|
+
debug.log('llm.openrouter', 'sticky-routing', { model: openRouterWireModel(activeModel), source: sticky.source, hashed: sticky.hashed });
|
|
10994
|
+
}
|
|
10799
10995
|
yield* streamOpenAIEvents(
|
|
10800
10996
|
useSub ? `${useSub.baseUrl}/chat/completions` : resolvedUrl,
|
|
10801
10997
|
useSub ? useSub.token : apiKey,
|
|
10802
10998
|
{
|
|
10803
10999
|
model: wire.model ? wire.model(activeModel) : activeModel,
|
|
10804
|
-
messages:
|
|
10805
|
-
acceptToolImagesViaFollowup: followup,
|
|
10806
|
-
acceptUserMessageImages: followup,
|
|
10807
|
-
...(name === 'openrouter' ? { echoReasoningDetails: true } : {}),
|
|
10808
|
-
})),
|
|
11000
|
+
messages: wireMessages,
|
|
10809
11001
|
...(() => {
|
|
10810
11002
|
const fields = openAiCompatSamplingFields(brand, activeModel, opts.temperature ?? 0.3, opts.maxTokens ?? 2048);
|
|
10811
11003
|
// ⛔ 2026-09-23 — OpenRouter 뒤의 추론 모델(kimi·glm·qwen …)은 기본 0.3 을 강제하면 안 된다:
|
|
@@ -10819,10 +11011,16 @@ function makeOpenAICompatProvider(
|
|
|
10819
11011
|
return fields;
|
|
10820
11012
|
})(),
|
|
10821
11013
|
...(tools ? { tools } : {}),
|
|
11014
|
+
...(toolChoice !== undefined ? { tool_choice: toolChoice } : {}),
|
|
10822
11015
|
...(wire.extraBody ?? {}),
|
|
11016
|
+
// OpenRouter alone resolves per-call effort against the configured level and catalog default.
|
|
11017
|
+
...(name === 'openrouter'
|
|
11018
|
+
? openRouterReasoningField(activeModel, opts.reasoningEffort, cfg.reasoningLevel)
|
|
11019
|
+
: {}),
|
|
11020
|
+
...(sticky ? { session_id: sticky.key } : {}),
|
|
10823
11021
|
},
|
|
10824
11022
|
opts.signal,
|
|
10825
|
-
useSub ? useSub.headers : wire.headers,
|
|
11023
|
+
useSub ? useSub.headers : (sticky ? { ...wire.headers, 'x-session-id': sticky.key } : wire.headers),
|
|
10826
11024
|
);
|
|
10827
11025
|
},
|
|
10828
11026
|
async *chat(messages, opts = {}) { yield* textOnly(this.streamChat!(messages, opts)); },
|
|
@@ -10842,7 +11040,18 @@ function makeOpenRouterProvider(cfg: UCLLMConfig): LLMProvider {
|
|
|
10842
11040
|
OPENROUTER_API_URL,
|
|
10843
11041
|
{ ...cfg, apiKey: cfg.apiKey || getOpenRouterApiKey() },
|
|
10844
11042
|
// ⭐ BACKLOG C7 — `usage:{include:true}` 면 마지막 청크 `usage.cost` 에 «실제 청구액»이 온다(추정 아님).
|
|
10845
|
-
{
|
|
11043
|
+
{
|
|
11044
|
+
model: openRouterWireModel, headers: { 'X-Title': 'elanous' }, omitDefaultTemperature: true, omitMaxTokens: true,
|
|
11045
|
+
extraBody: {
|
|
11046
|
+
usage: { include: true },
|
|
11047
|
+
provider: {
|
|
11048
|
+
require_parameters: true,
|
|
11049
|
+
allow_fallbacks: true,
|
|
11050
|
+
...(cfg.openrouter?.providerPreferences && typeof cfg.openrouter.providerPreferences === 'object' && !Array.isArray(cfg.openrouter.providerPreferences)
|
|
11051
|
+
? cfg.openrouter.providerPreferences : {}),
|
|
11052
|
+
},
|
|
11053
|
+
},
|
|
11054
|
+
},
|
|
10846
11055
|
);
|
|
10847
11056
|
// ⛔ 2026-09-23 — OpenRouter 의 `max_tokens` 는 «추론 토큰까지» 센다. 호환 경로 기본값 2048 이면 추론 모델이
|
|
10848
11057
|
// 본문·도구 호출에 닿기 전에 잘렸다(실측 glm-5.3: 2048 → finish=length). 오전 판은 바닥 16384 를 뒀고,
|
|
@@ -10851,11 +11060,77 @@ function makeOpenRouterProvider(cfg: UCLLMConfig): LLMProvider {
|
|
|
10851
11060
|
return inner;
|
|
10852
11061
|
}
|
|
10853
11062
|
|
|
11063
|
+
/** OR-TOOLARGS-REPAIR — 깨진 도구 인자 호출에 돌려주는 오류 문면(도구는 실행되지 않았다). */
|
|
11064
|
+
export function buildInvalidToolArgsMessage(info: ToolArgsInvalid): string {
|
|
11065
|
+
const truncated = info.finishReason === 'length';
|
|
11066
|
+
return `tool arguments were not valid JSON (${info.chars} chars` +
|
|
11067
|
+
(info.finishReason ? `, finish_reason=${info.finishReason}` : '') +
|
|
11068
|
+
`${truncated ? ' — the output was cut off at the length limit' : ' — truncated or malformed?'}). ` +
|
|
11069
|
+
'The tool was NOT executed. Re-issue the call with complete, valid JSON arguments' +
|
|
11070
|
+
(truncated ? ' (keep the payload smaller, e.g. split a large write into several calls).' : '.');
|
|
11071
|
+
}
|
|
11072
|
+
|
|
11073
|
+
/** OR-TOOLCHOICE-PASS — LLMOpts.toolChoice → OpenRouter `tool_choice` (`toChatToolChoice` 재사용).
|
|
11074
|
+
* ⚠️ Kimi(moonshotai/*)는 thinking 모드에서 강제 선택(required·특정 도구)을 400 으로 거부한다
|
|
11075
|
+
* (openclaw moonshot-thinking.ts:100-108 와 같은 처리) ⇒ 강제는 'auto' 로 내린다. */
|
|
11076
|
+
export function openRouterToolChoice(wireModel: string, tc: ToolChoice | undefined): unknown {
|
|
11077
|
+
const chat = toChatToolChoice(tc);
|
|
11078
|
+
if (chat === undefined) return undefined;
|
|
11079
|
+
if (wireModel.startsWith('moonshotai/') && chat !== 'auto' && chat !== 'none') return 'auto';
|
|
11080
|
+
return chat;
|
|
11081
|
+
}
|
|
11082
|
+
|
|
11083
|
+
/** OR-STICKY-ROUTING — OpenRouter 고정 라우팅 키. 본문 최상위 `session_id` ⊕ 헤더 `x-session-id` 로 싣는다
|
|
11084
|
+
* (hermes plugins/model-providers/openrouter build_extra_body: 본문 session_id 를 «라우팅 키»로 직접 쓰고 첫 성공
|
|
11085
|
+
* 요청부터 고정 · openclaw openai-completions-transport: openrouter 는 `x-session-id` 헤더 — `x-session-affinity` 는
|
|
11086
|
+
* openrouter 가 아닌 호환 게이트웨이용이라 여기선 안 쓴다).
|
|
11087
|
+
* 키 우선순위: 호출자의 대화 `sessionId` → 하니스 런 `ELANOUS_RUN_ID`. 둘 다 없으면 null(아무것도 안 싣는다).
|
|
11088
|
+
* 128자를 넘거나 허용 밖 문자가 있으면 sha256 앞 32자로 접는다(원문 id 를 상류에 안 흘린다는 부수 효과). */
|
|
11089
|
+
export function openRouterStickySessionKey(
|
|
11090
|
+
sessionId: string | undefined,
|
|
11091
|
+
runId: string | undefined,
|
|
11092
|
+
): { key: string; source: 'session' | 'run'; hashed: boolean } | null {
|
|
11093
|
+
// 공백뿐이면 «없음». 검사·해시는 원문 그대로 — 다듬으면 ' sess ' 와 'sess' 가 같은 키가 된다.
|
|
11094
|
+
const s = sessionId && sessionId.trim() ? sessionId : undefined;
|
|
11095
|
+
const r = runId && runId.trim() ? runId : undefined;
|
|
11096
|
+
const raw = s ?? r;
|
|
11097
|
+
if (!raw) return null;
|
|
11098
|
+
const source = s ? 'session' : 'run';
|
|
11099
|
+
if (raw.length <= 128 && /^[A-Za-z0-9._:-]+$/.test(raw)) return { key: raw, source, hashed: false };
|
|
11100
|
+
return { key: `elanous-${createHash('sha256').update(raw).digest('hex').slice(0, 32)}`, source, hashed: true };
|
|
11101
|
+
}
|
|
11102
|
+
|
|
10854
11103
|
/** `openrouter/moonshotai/kimi-k3` → `moonshotai/kimi-k3`. 접두가 없으면 그대로. */
|
|
10855
11104
|
export function openRouterWireModel(model: string): string {
|
|
10856
11105
|
return model.startsWith('openrouter/') ? model.slice('openrouter/'.length) : model;
|
|
10857
11106
|
}
|
|
10858
11107
|
|
|
11108
|
+
/** OpenRouter effort: call > resolved config (including escalation) > open-weight default.
|
|
11109
|
+
* Keep the existing effort mapping; Claude-family models use verbosity instead of reasoning. */
|
|
11110
|
+
const OPENROUTER_REASONING_EFFORT: Record<string, 'low' | 'medium' | 'high'> = {
|
|
11111
|
+
minimal: 'low', low: 'low', medium: 'medium', high: 'high', xhigh: 'high', max: 'high',
|
|
11112
|
+
};
|
|
11113
|
+
function openRouterReasoningField(
|
|
11114
|
+
model: string, requested: string | undefined, configured: UCLLMConfig['reasoningLevel'],
|
|
11115
|
+
): { reasoning?: { effort: 'low' | 'medium' | 'high' }; verbosity?: 'low' | 'medium' | 'high' } {
|
|
11116
|
+
const wireModel = openRouterWireModel(model);
|
|
11117
|
+
// The catalog's model-specific open-weight verdict, not a vendor/slug prefix,
|
|
11118
|
+
// gates the default: an unregistered release may be closed-weight.
|
|
11119
|
+
const slug = wireModel.slice(wireModel.indexOf('/') + 1);
|
|
11120
|
+
const openWeight = wireModel.includes('/') && BUILTIN_CATALOG.models.some(
|
|
11121
|
+
(entry) => entry.id === slug && entry.openWeight === true,
|
|
11122
|
+
);
|
|
11123
|
+
const configEffort = configured === 'off' ? undefined : configured;
|
|
11124
|
+
const source = requested !== undefined ? 'call' : configured !== undefined ? 'config' : openWeight ? 'default' : 'none';
|
|
11125
|
+
const effort = requested ?? (configured !== undefined ? configEffort : openWeight ? 'medium' : undefined);
|
|
11126
|
+
const sent = effort !== undefined && Object.hasOwn(OPENROUTER_REASONING_EFFORT, effort)
|
|
11127
|
+
? OPENROUTER_REASONING_EFFORT[effort] : undefined;
|
|
11128
|
+
const field = sent ? (wireModel.startsWith('anthropic/') ? 'verbosity' : 'reasoning') : 'none';
|
|
11129
|
+
debug.log('llm.openrouter', 'reasoning', { model, requested: requested ?? null, sent: sent ?? null, source, field });
|
|
11130
|
+
return field === 'verbosity' ? { verbosity: sent }
|
|
11131
|
+
: field === 'reasoning' ? { reasoning: { effort: sent! } } : {};
|
|
11132
|
+
}
|
|
11133
|
+
|
|
10859
11134
|
/** Codex-specific provider. Prefers OAuth tokens from ~/.config/elanous/auth.json
|
|
10860
11135
|
* (refreshing them when within the 120s buffer) and falls back to the
|
|
10861
11136
|
* plain apiKey flow only when no tokens are on file. OAuth mode targets
|
|
@@ -11200,6 +11475,7 @@ export function inferProviderFromModel(model: string | undefined): string | null
|
|
|
11200
11475
|
* its own configured default. */
|
|
11201
11476
|
export function isModelCompatible(providerName: string, model: string | undefined): boolean {
|
|
11202
11477
|
if (!model) return true;
|
|
11478
|
+
if (providerName === 'bedrock') return isBedrockCompatibleModel(model, inferProviderFromModel);
|
|
11203
11479
|
const implied = inferProviderFromModel(model);
|
|
11204
11480
|
if (implied === null) return true; // unknown prefix — let provider handle
|
|
11205
11481
|
// openai-codex and openai accept each other's model families (gpt-*, codex-*).
|
|
@@ -11239,7 +11515,7 @@ export function anyProviderAvailable(userConfig?: UserConfig): boolean {
|
|
|
11239
11515
|
} catch { return false; }
|
|
11240
11516
|
}
|
|
11241
11517
|
} catch { /* fall through to env check */ }
|
|
11242
|
-
return Object.values(PROVIDERS).some(p => p.available());
|
|
11518
|
+
return Object.values(PROVIDERS).some(p => p.name !== 'bedrock' && p.available()); // bedrock 은 auto 후보가 아니다
|
|
11243
11519
|
}
|
|
11244
11520
|
|
|
11245
11521
|
/** 직결 배선이 없는 계열 → OpenRouter 에서 그 벤더의 대표 모델(사다리 `openrouter` 에 선 것). */
|
|
@@ -11281,6 +11557,10 @@ export function getProviderForConfig(
|
|
|
11281
11557
|
if (!isKnownProviderName(resolvedProviderName)) {
|
|
11282
11558
|
throw new Error(`unknown provider: ${resolvedProviderName}`);
|
|
11283
11559
|
}
|
|
11560
|
+
if (resolvedProviderName === 'openrouter') {
|
|
11561
|
+
// Preserve the requesting config for OpenRouter, not the config-free singleton.
|
|
11562
|
+
return makeOpenRouterProvider({ provider: 'openrouter', model: decision.model, reasoningLevel: userConfig.llm.reasoningLevel });
|
|
11563
|
+
}
|
|
11284
11564
|
return PROVIDERS[resolvedProviderName]!;
|
|
11285
11565
|
}
|
|
11286
11566
|
if (!isKnownProviderName(resolvedProviderName)) {
|
|
@@ -11320,9 +11600,10 @@ export function getProviderForConfig(
|
|
|
11320
11600
|
case 'openai-codex':
|
|
11321
11601
|
return makeCodexProvider(llm);
|
|
11322
11602
|
case 'openrouter':
|
|
11323
|
-
return makeOpenRouterProvider(userConfig.llm.provider === 'openrouter' ? llm : { provider: 'openrouter', model: decision.model });
|
|
11603
|
+
return makeOpenRouterProvider(userConfig.llm.provider === 'openrouter' ? llm : { provider: 'openrouter', model: decision.model, reasoningLevel: llm.reasoningLevel });
|
|
11324
11604
|
case 'anthropic':
|
|
11325
11605
|
return makeAnthropicProvider(llm);
|
|
11606
|
+
case 'bedrock': return makeBedrockProvider(llm);
|
|
11326
11607
|
case 'gemini':
|
|
11327
11608
|
// Wave 1 (2026-05-04) — native @google/genai SDK. Previously
|
|
11328
11609
|
// makeOpenAICompatProvider tunnel which couldn't carry
|