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.
Files changed (780) hide show
  1. package/NOTICE +7 -0
  2. package/README.md +32 -22
  3. package/apps/pwa/out/404/index.html +1 -1
  4. package/apps/pwa/out/404.html +1 -1
  5. package/apps/pwa/out/_next/static/chunks/{119fc678.6f591cdb84ca5791.js → 0673cc54.8e2ef1c23e49e190.js} +1 -1
  6. package/apps/pwa/out/_next/static/chunks/{a9f2b54d-40c16bd0efdb04b8.js → 0a09e062-34f747a17d8d8c2e.js} +1 -1
  7. package/apps/pwa/out/_next/static/chunks/{f8626309.a4e5d362b1d55e59.js → 0e3acd34.d42b2ef87fdf4234.js} +1 -1
  8. package/apps/pwa/out/_next/static/chunks/1168.a0fb3d9db76c00bd.js +77 -0
  9. package/apps/pwa/out/_next/static/chunks/{7175-350f4ce2873bc038.js → 1325-dc3f3c21eb181cb4.js} +1 -1
  10. package/apps/pwa/out/_next/static/chunks/1357.a843c41d2cd7ec31.js +34 -0
  11. package/apps/pwa/out/_next/static/chunks/1430.53f49882b17607c2.js +24 -0
  12. package/apps/pwa/out/_next/static/chunks/1459-be6509b3419d8a9f.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/{6767.8e6c5f6e744fcd9f.js → 1505.5826671109111e75.js} +2 -2
  14. package/apps/pwa/out/_next/static/chunks/153.0a4e3cd516930491.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/1572.7bc291352e241a45.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/1593-d07ad068c120dfb0.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/1608.b7c900baa56cab32.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/1615-4d8156febaac4b35.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/1646.e03f0fbc26bc72f6.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/{7327-2d69fb321ba73389.js → 1669-da843ed73aa301f5.js} +1 -1
  21. package/apps/pwa/out/_next/static/chunks/176.13ba0659e3e96fd4.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/1990.9c60f495ef33c070.js +36 -0
  23. package/apps/pwa/out/_next/static/chunks/2042e469.f86158dd5c1e51a1.js +122 -0
  24. package/apps/pwa/out/_next/static/chunks/2528.0af5c0e1fad88df6.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/2543-28ec6aeb80a5e1e1.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/2561.43c99d6ee914ee6a.js +62 -0
  27. package/apps/pwa/out/_next/static/chunks/2638.b39ab2f674caa1a5.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/272-b23d2e92161d11fd.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/{7899.597af4a9996c907f.js → 2721.bc9a8f36bd85c07a.js} +1 -1
  30. package/apps/pwa/out/_next/static/chunks/2778.67e0c1d484189ccf.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/2841.10ff309f6a3168af.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/2886-9639f97d523d752a.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/2978.57fb87ce21cc5a85.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/3664.15f968c39d15bd28.js +149 -0
  35. package/apps/pwa/out/_next/static/chunks/3786-935eb3fcde90e496.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/3813.df4a01ae89c6f63f.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/3961-fbef064c213b2b18.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/3992.f79c70480e8c4077.js +309 -0
  39. package/apps/pwa/out/_next/static/chunks/40-413e8641de9ed1e5.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/4054-521f11a503daed64.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/4315.e7356f34c7d8ec79.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/4489-bf629de6f04f7681.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/4540.557733cc88c6a82b.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/462.0275b4338c5b6337.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/4658-7ed9266098a787e4.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/4945-0f4046cfc3228ea3.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/{d70879db.c66c56a95a91efc6.js → 4c5e95ce.83e9b16add6fcd8c.js} +1 -1
  48. package/apps/pwa/out/_next/static/chunks/5105-18b4165c5d3a86b0.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/5205-6992210fe31f45f4.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/5287-72898b126d722457.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/{6158.566c890adc06a459.js → 5313.1697309c532b9856.js} +2 -2
  52. package/apps/pwa/out/_next/static/chunks/{79b78388.663188133449d707.js → 53746282.1be36038d1abd949.js} +1 -1
  53. package/apps/pwa/out/_next/static/chunks/5474.991b90688c3cb321.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/5544-871146192d095594.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/5578.ac963634373b28c6.js +286 -0
  56. package/apps/pwa/out/_next/static/chunks/5935.d5e8ca3e096772e8.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/5967-c0a80f8ffe5d4050.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/{1268.0840ff91e083fcbd.js → 5974.360f8441eb0ac1ec.js} +1 -1
  59. package/apps/pwa/out/_next/static/chunks/6006.84e8b418a7a0db97.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/6013-1267ba7454d6764b.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/6038-1e0f7ee1086da4cf.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/617.709dd0019fe99796.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/6261.fb9bf94947094636.js +74 -0
  64. package/apps/pwa/out/_next/static/chunks/6411.1966866fae31ffa9.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/6481-b829d99aa8d158f5.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/6541.2b7daa043100d0fa.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/6571-926ddf024a6ad5df.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/6597.2d7a6d77ab485b27.js +64 -0
  69. package/apps/pwa/out/_next/static/chunks/67.5dd2dc543c2fa3de.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/{9832.2ab2e818013574c7.js → 6702.ebbd165d5e4a4a14.js} +1 -1
  71. package/apps/pwa/out/_next/static/chunks/6777-312496b0d774719b.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/681.0116f7036cfb4e8d.js +32 -0
  73. package/apps/pwa/out/_next/static/chunks/6871.30b2bf23b3126e36.js +24 -0
  74. package/apps/pwa/out/_next/static/chunks/6882.737d366d54e29d83.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/7035.54c2c535164b1c9b.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/7086-8bfa7e8f796a03d9.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/7126.5e5599f251726b67.js +93 -0
  78. package/apps/pwa/out/_next/static/chunks/7203-47ff0740a293e284.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/7268.017f49dafb5f0ff3.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/7355.5d65a87e9567ae08.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/7392.4018c2a62177f296.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/{6110.1297d4093fdfbb0d.js → 740.90b31555290236a9.js} +2 -2
  83. package/apps/pwa/out/_next/static/chunks/7471.3a3d1be50559cfb8.js +148 -0
  84. package/apps/pwa/out/_next/static/chunks/7500.73489a345cef2201.js +226 -0
  85. package/apps/pwa/out/_next/static/chunks/{9070.067c106528ec1ae6.js → 7518.49161e8f5814abdb.js} +1 -1
  86. package/apps/pwa/out/_next/static/chunks/7565.c2f72a15c1ed0396.js +27 -0
  87. package/apps/pwa/out/_next/static/chunks/7651.6d1c984d3d8587a4.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/7713.7ab863ed59b2d661.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/7793.d7cd2026767ddd54.js +115 -0
  90. package/apps/pwa/out/_next/static/chunks/7837.c7c267e5dceadb11.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/7891.09266382daf70d1c.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/7905.b230b9d06cb4ad5d.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/7990-cbf6a01bcbdcb7e6.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/8119-819c549e0c197786.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/8186-74ea19a3700d04a8.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/{8194.484f51e273d9abd2.js → 8264.00e434fbd02e9311.js} +16 -16
  97. package/apps/pwa/out/_next/static/chunks/8267-e7b3262b735ae106.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/8386.86518e55b75f7cf5.js +8 -0
  99. package/apps/pwa/out/_next/static/chunks/{088d8e8a.8069543d082bec12.js → 83cfc5c8.349535543c1548b6.js} +1 -1
  100. package/apps/pwa/out/_next/static/chunks/8437.ba6eeeb29590042f.js +23 -0
  101. package/apps/pwa/out/_next/static/chunks/{1948.5f35b39eef222a94.js → 8438.ee7f0df3b3f6fcb4.js} +1 -1
  102. package/apps/pwa/out/_next/static/chunks/8469-1500be57e582296f.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8483-7164cecdaf178ca6.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/{4588.ad3364cb7fb97ada.js → 8532.a86e99acf9b761cb.js} +2 -2
  105. package/apps/pwa/out/_next/static/chunks/8569.b853a8daa8f31d12.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/8722-4c940f02c496ad36.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/887-41d0dcf5af48c628.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/8925-2abfb48af477fb7f.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/{88729267.9c6c000157c83f2f.js → 89849432.9eaa2f4c9c010965.js} +3 -3
  110. package/apps/pwa/out/_next/static/chunks/9039.da86361496797522.js +90 -0
  111. package/apps/pwa/out/_next/static/chunks/905.d5745a25884754d4.js +94 -0
  112. package/apps/pwa/out/_next/static/chunks/9089-d909f3d4478b0628.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/9096.dc5c7a267f83790c.js +41 -0
  114. package/apps/pwa/out/_next/static/chunks/93.a567257b6bdb7fe4.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/9320.419acb9665b46597.js +287 -0
  116. package/apps/pwa/out/_next/static/chunks/9356.b8ceda6634612ff8.js +79 -0
  117. package/apps/pwa/out/_next/static/chunks/94.e9e1043b35cd3eed.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/9400-7498ea90b2e6ee8f.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/{3522-1de1319d028ac89c.js → 9502-32c5dc22e8f120f5.js} +3 -3
  120. package/apps/pwa/out/_next/static/chunks/9930-58644af9c813d6e1.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/9932.367cf4725fedd6e2.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/9935.1628b904cdc8ce0e.js +104 -0
  123. package/apps/pwa/out/_next/static/chunks/{7630.2b9a68659053ff4e.js → 9976.8f28864317639fe6.js} +16 -16
  124. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-a2aa8709d193ee0d.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/approvals/page-d5341ac96203a983.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-0160ab83c8685a12.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/board/page-55c631c032dcc47e.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/botlab/page-ad3bd8084048bee4.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/bots/page-e6784759a2531031.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/ceo/page-5c5d0e370f495ef6.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/chat/page-c325e21543cd48a8.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/consult/{page-111cabe4d1fd69ae.js → page-6168a7c43e6ef8f5.js} +1 -1
  133. package/apps/pwa/out/_next/static/chunks/app/control/page-31417d3604154a6d.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/decisions/page-e9606dc0bdec9305.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/design-check/page-a648bc464c9dc754.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/editor/page-25bb425afdb27541.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/exec/page-32d72fdef1afe11a.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/field/page-d27b794c8ba76bbb.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/healthz/route-a2aa8709d193ee0d.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/inside/page-2bd9ce9c020d02d4.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/intake/page-a34096245e63b9f2.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/layout-22170f4f00a15496.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/live/page-4cc66d22ca4ec502.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/live-run/page-83b14c729fcea837.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/loops/page-6e2781c523dad761.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/market/page-26dd415c8f13f341.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-ccdb83ed40c8d724.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/morning/page-7ad3de8fa06fdea9.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/not-found-015c02c4fec4023e.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/observatory/page-6b0ae5b5c42f6d2f.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-786111f30b6f0969.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-48fb31810693c357.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4e17cce5e2ed0fee.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/outputs/page-cb154acadb025414.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/page-16258e956ea93fc2.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/reflection/page-c2dd2b19c93f90ab.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-85f35dd1dd96ae87.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/sessions/page-d3c007c8a0ddd7ee.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-7837ce2aacb97b04.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/settings/page-7350ee93f4fe1033.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-00723458575f2b19.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/setup/layout-a2aa8709d193ee0d.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/setup/page-745d9b6c015076f8.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/share/page-736d33c7414a8a1a.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/showroom/page-119be9a0444d2482.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/tasks/page-fa806c018833e332.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/term/page-c782041b5f5199ba.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/today/page-d431fbdea6ad93dd.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/trace/page-0c056abff82b9891.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/vault/page-242d668e4fbf72c4.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-847c3de6ca8a4416.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/workflows/page-81dd0d8ae923ed72.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/app/workspace/page-74e69ba2c8e970d4.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-70038f41ae7cf931.js +1 -0
  175. package/apps/pwa/out/_next/static/chunks/b4e12462-5fab4a813a63dadd.js +1 -0
  176. package/apps/pwa/out/_next/static/chunks/cd39fa05.fac4545f42a3ef70.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/{f6b7c9ba.64a895b8b2fedbdc.js → ce383d63.d2ede338788ed18e.js} +1 -1
  178. package/apps/pwa/out/_next/static/chunks/{framework-5c169757551134ed.js → framework-b2763b10dc6b3836.js} +1 -1
  179. package/apps/pwa/out/_next/static/chunks/main-app-27893e93b0ec193d.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-f280047194e1daf8.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-e90eff2d0b70564c.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-70f2d654b3435d34.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-4794f053bd5e4230.js +1 -0
  184. package/apps/pwa/out/_next/static/css/5619d59e87eddf66.css +1 -0
  185. package/apps/pwa/out/_next/static/css/d0a48dc099ed86cf.css +1 -0
  186. package/apps/pwa/out/_next/static/{MObU8ujkMciAKr6ljAV05 → rfkMm4movqkqMebBrCXiR}/_buildManifest.js +1 -1
  187. package/apps/pwa/out/approvals/index.html +1 -1
  188. package/apps/pwa/out/approvals/index.txt +23 -23
  189. package/apps/pwa/out/autopilot/index.html +1 -1
  190. package/apps/pwa/out/autopilot/index.txt +23 -23
  191. package/apps/pwa/out/board/index.html +1 -1
  192. package/apps/pwa/out/board/index.txt +23 -23
  193. package/apps/pwa/out/botlab/index.html +1 -1
  194. package/apps/pwa/out/botlab/index.txt +22 -22
  195. package/apps/pwa/out/bots/index.html +1 -1
  196. package/apps/pwa/out/bots/index.txt +22 -22
  197. package/apps/pwa/out/ceo/index.html +1 -1
  198. package/apps/pwa/out/ceo/index.txt +23 -23
  199. package/apps/pwa/out/chat/index.html +1 -1
  200. package/apps/pwa/out/chat/index.txt +22 -22
  201. package/apps/pwa/out/consult/index.html +1 -1
  202. package/apps/pwa/out/consult/index.txt +23 -23
  203. package/apps/pwa/out/control/index.html +1 -1
  204. package/apps/pwa/out/control/index.txt +23 -23
  205. package/apps/pwa/out/decisions/index.html +1 -1
  206. package/apps/pwa/out/decisions/index.txt +22 -22
  207. package/apps/pwa/out/design-check/index.html +1 -1
  208. package/apps/pwa/out/design-check/index.txt +23 -23
  209. package/apps/pwa/out/editor/index.html +1 -1
  210. package/apps/pwa/out/editor/index.txt +24 -23
  211. package/apps/pwa/out/exec/index.html +1 -1
  212. package/apps/pwa/out/exec/index.txt +23 -23
  213. package/apps/pwa/out/field/index.html +1 -1
  214. package/apps/pwa/out/field/index.txt +23 -23
  215. package/apps/pwa/out/healthz +1 -1
  216. package/apps/pwa/out/index.html +1 -1
  217. package/apps/pwa/out/index.txt +22 -22
  218. package/apps/pwa/out/inside/index.html +1 -1
  219. package/apps/pwa/out/inside/index.txt +22 -22
  220. package/apps/pwa/out/intake/index.html +1 -1
  221. package/apps/pwa/out/intake/index.txt +23 -23
  222. package/apps/pwa/out/live/index.html +1 -1
  223. package/apps/pwa/out/live/index.txt +23 -23
  224. package/apps/pwa/out/live-run/index.html +1 -1
  225. package/apps/pwa/out/live-run/index.txt +24 -23
  226. package/apps/pwa/out/loops/index.html +1 -1
  227. package/apps/pwa/out/loops/index.txt +22 -22
  228. package/apps/pwa/out/market/index.html +1 -1
  229. package/apps/pwa/out/market/index.txt +22 -22
  230. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  231. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  232. package/apps/pwa/out/morning/index.html +1 -1
  233. package/apps/pwa/out/morning/index.txt +23 -23
  234. package/apps/pwa/out/observatory/index.html +1 -1
  235. package/apps/pwa/out/observatory/index.txt +23 -23
  236. package/apps/pwa/out/ops/checklist/index.html +1 -1
  237. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  238. package/apps/pwa/out/ops/release/index.html +1 -1
  239. package/apps/pwa/out/ops/release/index.txt +22 -22
  240. package/apps/pwa/out/ops/seats/index.html +1 -1
  241. package/apps/pwa/out/ops/seats/index.txt +22 -22
  242. package/apps/pwa/out/outputs/index.html +1 -1
  243. package/apps/pwa/out/outputs/index.txt +22 -22
  244. package/apps/pwa/out/reflection/index.html +1 -1
  245. package/apps/pwa/out/reflection/index.txt +23 -23
  246. package/apps/pwa/out/scheduler/index.html +1 -1
  247. package/apps/pwa/out/scheduler/index.txt +23 -23
  248. package/apps/pwa/out/sessions/index.html +1 -1
  249. package/apps/pwa/out/sessions/index.txt +22 -22
  250. package/apps/pwa/out/settings/devices/index.html +1 -1
  251. package/apps/pwa/out/settings/devices/index.txt +23 -23
  252. package/apps/pwa/out/settings/index.html +1 -1
  253. package/apps/pwa/out/settings/index.txt +23 -23
  254. package/apps/pwa/out/setup/done/index.html +1 -1
  255. package/apps/pwa/out/setup/done/index.txt +23 -23
  256. package/apps/pwa/out/setup/index.html +1 -1
  257. package/apps/pwa/out/setup/index.txt +23 -23
  258. package/apps/pwa/out/share/index.html +1 -1
  259. package/apps/pwa/out/share/index.txt +23 -23
  260. package/apps/pwa/out/showroom/index.html +1 -1
  261. package/apps/pwa/out/showroom/index.txt +22 -22
  262. package/apps/pwa/out/tasks/index.html +1 -1
  263. package/apps/pwa/out/tasks/index.txt +23 -23
  264. package/apps/pwa/out/term/index.html +1 -1
  265. package/apps/pwa/out/term/index.txt +23 -23
  266. package/apps/pwa/out/today/index.html +1 -1
  267. package/apps/pwa/out/today/index.txt +23 -23
  268. package/apps/pwa/out/trace/index.html +1 -1
  269. package/apps/pwa/out/trace/index.txt +23 -23
  270. package/apps/pwa/out/vault/index.html +1 -1
  271. package/apps/pwa/out/vault/index.txt +23 -23
  272. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  273. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  274. package/apps/pwa/out/workflows/index.html +1 -1
  275. package/apps/pwa/out/workflows/index.txt +23 -23
  276. package/apps/pwa/out/workspace/index.html +1 -1
  277. package/apps/pwa/out/workspace/index.txt +23 -23
  278. package/apps/pwa/out/worktrees/index.html +1 -1
  279. package/apps/pwa/out/worktrees/index.txt +23 -23
  280. package/catalog/models/anthropic/claude-haiku-5-5.yaml +32 -0
  281. package/catalog/models/anthropic/claude-opus-5-5.yaml +5 -0
  282. package/catalog/models/anthropic/claude-sonnet-5-5.yaml +31 -0
  283. package/catalog/models/anthropic/claude-sonnet-5.yaml +8 -2
  284. package/catalog/models/openai/gpt-6-astra.yaml +6 -0
  285. package/catalog/models/openai/gpt-6-luna.yaml +6 -0
  286. package/catalog/models/openai/gpt-6-sol.yaml +6 -0
  287. package/graphs/catalog/catalog.yaml +1 -1
  288. package/graphs/drafts/recipes.yaml +2 -2
  289. package/graphs/log-horizon/log-horizon-watch.yaml +25 -0
  290. package/graphs/log-horizon/recipes.yaml +3 -0
  291. package/graphs/release/recipes.yaml +1 -1
  292. package/graphs/release/release-loop.yaml +6 -2
  293. package/graphs/release-rehearsal/recipes.yaml +12 -0
  294. package/graphs/release-rehearsal/release-rehearsal.yaml +17 -0
  295. package/graphs/test-diet/recipes.yaml +3 -0
  296. package/graphs/test-diet/test-diet.yaml +3 -1
  297. package/package.json +4 -1
  298. package/scripts/bench-report.ts +82 -3
  299. package/scripts/ci-typecheck-changed.ts +10 -1
  300. package/scripts/f-session-monitor.ts +69 -0
  301. package/scripts/hq/hq-fence-wrapper.sh +148 -0
  302. package/scripts/hq/standby-snapshot.ts +7 -3
  303. package/scripts/knowledge-compress.ts +11 -0
  304. package/scripts/lib/typecheck-ratchet.ts +51 -0
  305. package/scripts/nightly-docops.ts +90 -3
  306. package/scripts/openai-relay-server.ts +5 -1
  307. package/scripts/release-loop/docs-node.ts +258 -43
  308. package/scripts/release-loop/gate-method.ts +59 -0
  309. package/scripts/release-loop/gate-node.ts +73 -7
  310. package/scripts/release-loop/gate-wall.ts +208 -0
  311. package/scripts/release-loop/known-issues-node.ts +53 -8
  312. package/scripts/release-loop/publish-at.ts +14 -0
  313. package/scripts/release-loop/publish-node.ts +17 -2
  314. package/scripts/release-loop/resume-release.ts +34 -4
  315. package/scripts/release-loop/resume.ts +53 -0
  316. package/scripts/release-loop/shard-plan.ts +3 -11
  317. package/scripts/release-loop/tui-node-checks.ts +22 -0
  318. package/scripts/release-loop/unattended-release.ts +8 -1
  319. package/scripts/research-coo-admin-dates.ts +39 -0
  320. package/scripts/rhythm/daily.ts +51 -2
  321. package/scripts/rhythm/weekly.ts +3 -2
  322. package/scripts/skills/public-check.ts +7 -2
  323. package/scripts/smart-merge/resync-shadow.ts +5 -3
  324. package/scripts/test-diet/lib.ts +81 -1
  325. package/scripts/test-diet/node.ts +48 -2
  326. package/scripts/tsc-main-safety-net.ts +189 -0
  327. package/scripts/usage-rollup.ts +8 -4
  328. package/scripts/verify-coo-admin-evidence.ts +83 -0
  329. package/src/acp/client.ts +4 -2
  330. package/src/acp/codex-plugins.ts +48 -6
  331. package/src/agent/monad-agent-turn.ts +67 -5
  332. package/src/agent/run-context.ts +14 -0
  333. package/src/agent/tool-profile.ts +28 -2
  334. package/src/agent-env/profile.ts +25 -5
  335. package/src/agent-mission/acp-judge.ts +8 -2
  336. package/src/agent-mission/capabilities-cli.ts +16 -1
  337. package/src/agent-mission/driver.ts +27 -13
  338. package/src/agent-mission/pr-review-watch.ts +6 -2
  339. package/src/agent-mission/review-loop.ts +33 -5
  340. package/src/agent-mission/supervisor-metrics.ts +17 -2
  341. package/src/agent-substrate/acp-reviewer.ts +25 -9
  342. package/src/agent-substrate/pr-reviewer.ts +175 -32
  343. package/src/agent-substrate/review-intent.ts +106 -5
  344. package/src/agent-substrate/self-review-cli.ts +111 -16
  345. package/src/agent-substrate/shard-boundary-intent.ts +92 -26
  346. package/src/ask-user-question/pending-questions.ts +8 -2
  347. package/src/autopilot/build/llm-conflict-merge.ts +238 -20
  348. package/src/autopilot/codebase-grounding.ts +44 -0
  349. package/src/autopilot/llm-control-brain.ts +13 -1
  350. package/src/autopilot/mission-codebase-gate.ts +8 -77
  351. package/src/autopilot/pr-manager.ts +30 -11
  352. package/src/away/release-watch.ts +47 -8
  353. package/src/boot/acp-server.ts +4 -7
  354. package/src/boot/acp-socket-path.ts +7 -0
  355. package/src/briefing/brief-items.ts +123 -22
  356. package/src/chat/index.ts +13 -3
  357. package/src/cli/agent-cli.ts +20 -0
  358. package/src/cli/brief-cli.ts +46 -22
  359. package/src/cli/cli-user-error.ts +9 -2
  360. package/src/cli/config-classify.ts +83 -0
  361. package/src/cli/control-cli.ts +14 -0
  362. package/src/cli/decisions-cli.ts +26 -16
  363. package/src/cli/log-event-names.ts +3 -0
  364. package/src/cli/logs-cli.ts +1 -0
  365. package/src/cli/logs-model-input.ts +1 -1
  366. package/src/cli/mcp-login.ts +111 -37
  367. package/src/cli/plugin-cli.ts +21 -1
  368. package/src/cli/pod-cli.ts +26 -0
  369. package/src/cli/pr-cli.ts +94 -9
  370. package/src/cli/pr-land-overlap-evidence.ts +131 -0
  371. package/src/cli/release-cli.ts +74 -15
  372. package/src/cli/self-update.ts +173 -10
  373. package/src/cli/skills-cli.ts +12 -3
  374. package/src/cli/tasks-cli.ts +241 -28
  375. package/src/connectors/types.ts +6 -6
  376. package/src/context-bus/context-first.ts +51 -2
  377. package/src/context-bus/context-now-surfaces.ts +29 -0
  378. package/src/context-bus/coord-events.ts +32 -4
  379. package/src/context-bus/long-term-memory.ts +26 -7
  380. package/src/context-bus/nightly-condense.ts +170 -21
  381. package/src/control/control-status.ts +87 -0
  382. package/src/control-plane/light-member.ts +5 -3
  383. package/src/control-plane/member.ts +172 -7
  384. package/src/core-turn/run-goal-loop.ts +108 -3
  385. package/src/dashboard/chat-fold.ts +20 -0
  386. package/src/dashboard/first-screen-band.ts +151 -1
  387. package/src/dashboard/index.ts +27 -5
  388. package/src/dashboard/slash-runtime/dashboard-handlers.ts +14 -3
  389. package/src/dashboard/stale-install-check.ts +13 -2
  390. package/src/dashboard/turn-stream-formatter.ts +25 -0
  391. package/src/debug/log-diet.ts +159 -0
  392. package/src/debug/log.ts +52 -17
  393. package/src/decisions/decision-cards.ts +20 -1
  394. package/src/decisions/decision-ledger.ts +11 -8
  395. package/src/decisions/web-push-decision-cards.ts +19 -3
  396. package/src/discord-self-message.ts +2 -2
  397. package/src/display/coordinator.ts +25 -2
  398. package/src/domains/coo-admin-dates.evidence.json +876 -0
  399. package/src/domains/coo-admin-tool.ts +75 -14
  400. package/src/domains/cron-match.ts +1 -0
  401. package/src/domains/ops-status.ts +53 -0
  402. package/src/domains/outbound-alert.ts +41 -7
  403. package/src/domains/release-tool.ts +119 -10
  404. package/src/domains/schedule-registry.ts +10 -7
  405. package/src/domains/schedule-runner.ts +1 -0
  406. package/src/elanous-config-dir.ts +2 -2
  407. package/src/elanous-daemon.ts +3 -3
  408. package/src/exec-requests/planner.ts +6 -0
  409. package/src/execution-loop/launch-gate.ts +1 -1
  410. package/src/expression/i18n/messages.en.ts +5 -0
  411. package/src/expression/i18n/messages.ja.ts +5 -0
  412. package/src/expression/i18n/messages.ko.ts +5 -0
  413. package/src/expression/i18n/messages.zh.ts +5 -0
  414. package/src/expression/i18n/types.ts +8 -0
  415. package/src/github/pr-labels.ts +1 -0
  416. package/src/graph-kinds/registry.ts +6 -6
  417. package/src/graph-runner/graph-cli.ts +34 -2
  418. package/src/graph-runner/graph-run-api.ts +7 -0
  419. package/src/graph-runner/graph-tick.ts +73 -12
  420. package/src/graph-runner/runner.ts +94 -13
  421. package/src/graph-unify/wf-to-graph.ts +79 -0
  422. package/src/graph-wizard/generate.ts +34 -2
  423. package/src/graph-wizard/steps.ts +13 -0
  424. package/src/harness/dispatch-backpressure.ts +259 -0
  425. package/src/harness/harness-cli-command.ts +227 -50
  426. package/src/harness/harness-queue.ts +58 -14
  427. package/src/harness/harness-seams.ts +2 -20
  428. package/src/harness/harness-substrate-default.ts +72 -1
  429. package/src/harness/launch-advice.ts +23 -0
  430. package/src/harness/nested-elanous-policy.ts +4 -2
  431. package/src/hq/fence-wrapper.ts +7 -0
  432. package/src/hq/hq.ts +33 -2
  433. package/src/hq/lease.ts +13 -0
  434. package/src/hq/seats.ts +114 -18
  435. package/src/index.ts +199 -71
  436. package/src/intake-plane/collect-github.ts +19 -1
  437. package/src/intake-plane/digest.ts +45 -20
  438. package/src/intake-plane/lens.ts +36 -8
  439. package/src/intelligence-map/model-alias.ts +6 -0
  440. package/src/intelligence-map/model-catalog.ts +41 -0
  441. package/src/knowledge/conclusion-compress.ts +93 -0
  442. package/src/knowledge/kgs/pack.ts +5 -2
  443. package/src/knowledge/kgs/sqlite-store.ts +15 -0
  444. package/src/knowledge/know-find.ts +9 -2
  445. package/src/knowledge/query.ts +20 -0
  446. package/src/knowledge/tools/knowledge-query.ts +20 -2
  447. package/src/knowledge/write.ts +234 -2
  448. package/src/llm/bedrock-provider.ts +175 -0
  449. package/src/llm/bedrock.ts +345 -0
  450. package/src/llm/provider-credentials.ts +3 -1
  451. package/src/llm.ts +332 -51
  452. package/src/loops/budget.ts +150 -0
  453. package/src/loops/neighbor-runtime.ts +88 -0
  454. package/src/loops/orchestrator/author-depth.ts +29 -11
  455. package/src/loops/orchestrator/overlap.ts +7 -1
  456. package/src/loops/orchestrator/resync-shadow.ts +1 -1
  457. package/src/loops/orchestrator/seat-share.ts +6 -49
  458. package/src/loops/orchestrator/tick.ts +35 -2
  459. package/src/loops/orchestrator/traffic.ts +6 -80
  460. package/src/loops/registry.ts +5 -0
  461. package/src/market/publish.ts +17 -1
  462. package/src/market/signed-index.ts +42 -0
  463. package/src/maturity/feature-maturity.ts +2 -1
  464. package/src/mcp/mcp-oauth.ts +136 -17
  465. package/src/model-tier/llm-tier-map.ts +48 -4
  466. package/src/models/prompts.ts +22 -1
  467. package/src/mss/logging/horizon-watch.ts +168 -0
  468. package/src/mss/logging/log-store.ts +204 -15
  469. package/src/mss/logging/redaction.ts +17 -0
  470. package/src/native-tool-catalog.ts +1 -1
  471. package/src/nexus/api/consult-requests.ts +7 -10
  472. package/src/nexus/api/discord-trigger-bot.ts +6 -3
  473. package/src/nexus/api/draft-metrics.ts +22 -8
  474. package/src/nexus/api/error-reports.ts +30 -8
  475. package/src/nexus/api/graph-peer-edit.ts +77 -0
  476. package/src/nexus/api/graph-wizard-api.ts +9 -1
  477. package/src/nexus/api/graphs-api.ts +145 -7
  478. package/src/nexus/api/http-server.ts +101 -8
  479. package/src/nexus/api/loop-resources.ts +42 -0
  480. package/src/nexus/api/outbound-report.ts +8 -3
  481. package/src/nexus/api/plugins-market.ts +24 -0
  482. package/src/nexus/api/telegram-trigger-bot.ts +6 -3
  483. package/src/nexus/index.ts +13 -2
  484. package/src/nexus/outbound/format.ts +2 -0
  485. package/src/nexus/outbound/router.ts +198 -13
  486. package/src/oauth/claude-pty-maturity.ts +24 -0
  487. package/src/oauth/codex-account-rotation.ts +16 -18
  488. package/src/oauth/codex-account-store.ts +134 -5
  489. package/src/oauth/fallback-chain.ts +50 -15
  490. package/src/onboarding.ts +2 -1
  491. package/src/plugins/adapters/claude-package.ts +4 -12
  492. package/src/plugins/core/capability-policy.ts +141 -0
  493. package/src/plugins/core/host.ts +21 -8
  494. package/src/plugins/core/manifest.ts +19 -2
  495. package/src/plugins/core/trust-store.ts +15 -0
  496. package/src/plugins/core/types.ts +12 -0
  497. package/src/plugins/install/market-fetch.ts +68 -16
  498. package/src/plugins/install/plugin-install.ts +187 -16
  499. package/src/plugins/maker/market-bundle.ts +9 -0
  500. package/src/plugins/maker/plugin-maker.ts +32 -21
  501. package/src/plugins/maker/wizard-generate.ts +87 -9
  502. package/src/policy/llm-policy.ts +24 -6
  503. package/src/process/pid-liveness.ts +1 -1
  504. package/src/prompt-cache/openai.ts +10 -6
  505. package/src/prompt-cache/openrouter.ts +94 -0
  506. package/src/prompt-enhance/enhance.ts +46 -5
  507. package/src/prompt-library/family-prompt-coverage.ts +1 -0
  508. package/src/prompt-library/universal-preamble.ts +2 -2
  509. package/src/registry/discovery/openrouter-live-resolve.ts +122 -0
  510. package/src/registry/loader.ts +6 -1
  511. package/src/release-loop/checklist-board.ts +27 -0
  512. package/src/release-loop/checklist.ts +62 -9
  513. package/src/release-loop/feature-store.ts +3 -0
  514. package/src/release-loop/gate-shards.ts +48 -4
  515. package/src/release-loop/landed-to-green.ts +81 -0
  516. package/src/release-loop/light-rc.ts +11 -1
  517. package/src/release-loop/merged-pr-checklist.ts +10 -0
  518. package/src/release-loop/placement.ts +91 -22
  519. package/src/release-loop/rehearsal.ts +317 -0
  520. package/src/release-loop/release-schedule.ts +13 -1
  521. package/src/release-loop/rubric-types.ts +1 -0
  522. package/src/release-loop/rubric.ts +2 -2
  523. package/src/retro/daily.ts +23 -9
  524. package/src/seat-address/seat-address.ts +1 -0
  525. package/src/seat-loop/seat-loop.ts +208 -21
  526. package/src/seat-loop/seat-report.ts +29 -1
  527. package/src/seat-loop/traffic-signal.ts +44 -0
  528. package/src/self-dev/ask-launch-flow.ts +2 -2
  529. package/src/self-dev/dev-cli.ts +157 -11
  530. package/src/self-dev/dev-pipeline.ts +18 -1
  531. package/src/self-dev/draft-residue.ts +463 -0
  532. package/src/self-dev/draft-sweep.ts +195 -17
  533. package/src/self-dev/draft-triage-rules.ts +27 -1
  534. package/src/self-dev/launch-preflight-text.ts +549 -0
  535. package/src/self-dev/launch-preflight.ts +10 -545
  536. package/src/self-dev/orchestrate-cli.ts +57 -2
  537. package/src/self-dev/orchestrate-summary-line.ts +13 -0
  538. package/src/self-dev/orchestrate.ts +9 -133
  539. package/src/self-dev/review-provider-fallback.ts +179 -0
  540. package/src/self-dev/run-store.ts +1 -3
  541. package/src/self-dev/run-supervisor.ts +8 -23
  542. package/src/self-dev/run-types.ts +178 -0
  543. package/src/self-dev/shard-aggregate.ts +61 -13
  544. package/src/self-dev/shard-plan.ts +5 -1
  545. package/src/self-dev/shard-run.ts +23 -5
  546. package/src/self-dev/supervisor-verdict-edges.ts +2 -4
  547. package/src/self-implement/blocked-draft-policy.ts +3 -19
  548. package/src/self-implement/draft-on-stop-mode.ts +18 -0
  549. package/src/self-implement/follow-up-goals.ts +114 -38
  550. package/src/self-implement/gate-baseline-reap.ts +157 -0
  551. package/src/self-implement/gate-baseline.ts +78 -16
  552. package/src/self-implement/gate-cli.ts +12 -2
  553. package/src/self-implement/gate-remote.ts +17 -6
  554. package/src/self-implement/goal-author.ts +24 -4
  555. package/src/self-implement/goal-digest.ts +19 -0
  556. package/src/self-implement/graph-overlay-condition.ts +4 -0
  557. package/src/self-implement/harness-policy-gates.ts +7 -5
  558. package/src/self-implement/headless-elanous-driver.ts +11 -9
  559. package/src/self-implement/host-regate.ts +148 -43
  560. package/src/self-implement/l8-merge-queue.ts +147 -13
  561. package/src/self-implement/merge-train.ts +131 -0
  562. package/src/self-implement/off-diff-evidence.ts +9 -0
  563. package/src/self-implement/orchestrator.ts +201 -43
  564. package/src/self-implement/review-finding-recurrence.ts +28 -0
  565. package/src/self-implement/rework-policy.ts +2 -1
  566. package/src/self-implement/round-summary-card.ts +63 -0
  567. package/src/self-implement/run-ledger.ts +4 -3
  568. package/src/self-implement/run-step-projection.ts +147 -0
  569. package/src/self-implement/run-stop.ts +1 -1
  570. package/src/self-implement/seams.ts +41 -6
  571. package/src/self-implement/self-implement-cli.ts +6 -0
  572. package/src/self-implement/train-gate-remote.ts +158 -0
  573. package/src/session-runtime/index.ts +10 -1
  574. package/src/session-runtime/retry-api.ts +11 -1
  575. package/src/shell-env-bootstrap.ts +19 -4
  576. package/src/skills/gift-install.ts +119 -0
  577. package/src/skills/runner.ts +59 -2
  578. package/src/skills/skill-feedback.ts +31 -1
  579. package/src/skills/skill-tier.ts +1 -0
  580. package/src/smart-wizard/capability-index.ts +231 -0
  581. package/src/smart-wizard/rung.ts +74 -0
  582. package/src/steward/launch.ts +20 -9
  583. package/src/steward/triage.ts +29 -10
  584. package/src/storage/file-lock.ts +40 -4
  585. package/src/task-agent/actions.ts +4 -0
  586. package/src/task-agent/card-evidence.ts +59 -13
  587. package/src/task-agent/completion-evidence.ts +31 -3
  588. package/src/task-agent/cover.ts +61 -0
  589. package/src/task-agent/judge.ts +4 -3
  590. package/src/task-agent/land-worktree.ts +201 -0
  591. package/src/task-agent/live-move-history.ts +133 -0
  592. package/src/task-agent/live-moves.ts +222 -12
  593. package/src/task-agent/parent-host.ts +117 -8
  594. package/src/task-agent/rejudge-on-head.ts +297 -0
  595. package/src/task-agent/review-result-capture.ts +218 -0
  596. package/src/task-agent/shadow.ts +118 -7
  597. package/src/task-agent/task-hand.ts +138 -11
  598. package/src/task-orchestrator/surfaces/pod-child-providers.ts +29 -0
  599. package/src/task-orchestrator/surfaces/pod-command-job.ts +6 -3
  600. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +16 -2
  601. package/src/task-orchestrator/surfaces/pod-image-source.ts +212 -0
  602. package/src/task-orchestrator/surfaces/pod-lease.ts +93 -12
  603. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +25 -2
  604. package/src/task-orchestrator/surfaces/pod-pool.ts +203 -28
  605. package/src/task-orchestrator/surfaces/self-implement-pod.ts +259 -36
  606. package/src/task-orchestrator/surfaces/self-implement.ts +11 -0
  607. package/src/telegram-commands.ts +8 -0
  608. package/src/telegram-project-command.ts +6 -0
  609. package/src/telegram-service.ts +5 -1
  610. package/src/telegram.ts +17 -4
  611. package/src/time/format.ts +13 -4
  612. package/src/tool-runtime/goal-author-runtime.ts +1 -0
  613. package/src/tool-runtime/self-cognition-catalog.ts +23 -0
  614. package/src/tool-runtime/self-cognition-runtimes.ts +2 -24
  615. package/src/typecheck-ratchet.ts +2 -1
  616. package/src/user-config.ts +167 -28
  617. package/src/ux-sim/slash-menu-frames.ts +168 -0
  618. package/src/version/packed-revision.json +1 -1
  619. package/src/web-terminal/preview-tap-registry.ts +5 -2
  620. package/src/workflow-runtime/executor.ts +24 -2
  621. package/src/workflow-runtime/triggers/registry.ts +27 -0
  622. package/src/workflow-runtime/triggers/schedule-source.ts +30 -3
  623. package/src/workflow-runtime/triggers/scheduler.ts +1 -0
  624. package/apps/pwa/out/_next/static/chunks/1109.78a7a3288c0259d9.js +0 -148
  625. package/apps/pwa/out/_next/static/chunks/115.1c6690b8604f81c4.js +0 -32
  626. package/apps/pwa/out/_next/static/chunks/1262.76a3f08e67c5f816.js +0 -309
  627. package/apps/pwa/out/_next/static/chunks/1307-c97eba9fb72a9a5e.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/1358d292.5c87f12cad6eaa91.js +0 -122
  629. package/apps/pwa/out/_next/static/chunks/1438.27a1a7b8f2308004.js +0 -149
  630. package/apps/pwa/out/_next/static/chunks/1442.02d85cd88f4c1eac.js +0 -79
  631. package/apps/pwa/out/_next/static/chunks/1501-1aad662d82ba43f7.js +0 -1
  632. package/apps/pwa/out/_next/static/chunks/1584.9e2dd53da6e6d4b1.js +0 -24
  633. package/apps/pwa/out/_next/static/chunks/1586.b989b0614afb77e6.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/1609.2ad355062870151f.js +0 -1
  635. package/apps/pwa/out/_next/static/chunks/1612-f6df0fc0eed7157b.js +0 -1
  636. package/apps/pwa/out/_next/static/chunks/1826-5d279da64bbbc2de.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/1923.37f1d5fe7ebe3860.js +0 -27
  638. package/apps/pwa/out/_next/static/chunks/195-fb1d7690bf30bab4.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/1986-33e13d648a9df765.js +0 -1
  640. package/apps/pwa/out/_next/static/chunks/1993.3fd074a2a246234e.js +0 -1
  641. package/apps/pwa/out/_next/static/chunks/211-9c9090c59e2c5907.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/2140.d2daf9ee96e295d1.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/2212.0359851457473efc.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/224.583e562365a52f74.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/2328.0f37465646bafa7d.js +0 -36
  647. package/apps/pwa/out/_next/static/chunks/2372.bf71372184991937.js +0 -286
  648. package/apps/pwa/out/_next/static/chunks/2489-ff55a35b202c0f94.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/2537-6c289376caa88ca1.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/2549-a8515c86f9e8cb96.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/2655.72cc6a97276c5acc.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/2699-325cc923ba7b8631.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/2743-ef6e8c3ced74cce5.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/2840-5458ad50c49cac6a.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/2856.f75d5baef7f49b74.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/311.e685738f92e6e2ec.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/3344.0de4b0ec5a454b7a.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/335.a13f339e97893437.js +0 -94
  661. package/apps/pwa/out/_next/static/chunks/3394.646348f34b2500be.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/3443.6276909b53d72d53.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/3495.abd4254d808bf2dc.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/3558-bbb5ab553a0471d3.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/3721.ba5b82db0d9a5572.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/3857-995ea9f5ef33d71e.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/3919.9ff7dc25afefee33.js +0 -74
  669. package/apps/pwa/out/_next/static/chunks/3998.bd9a69d9b50e9bd2.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/4003.ab6db1dc266576c9.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/4144-fad095b48a1862ee.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/4216.e8ac94b9fe6b96ab.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/4327.c44dc2b55cb43ee5.js +0 -34
  674. package/apps/pwa/out/_next/static/chunks/4401.94257d497b6d26bc.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/4559.17ca2cdbaa8d414f.js +0 -115
  676. package/apps/pwa/out/_next/static/chunks/4565-3d7e3fdeb43686a8.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/4706.97e734bd4c9816ca.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/4795-f372490b178583fc.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/4982.6e44352f751b9a1b.js +0 -77
  680. package/apps/pwa/out/_next/static/chunks/5342.49c5c5a530e62b50.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/5360-08a80abdf3a4da99.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/5431.66c58ab1327ee0b7.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/5717.bcfcb96e701b82e0.js +0 -90
  684. package/apps/pwa/out/_next/static/chunks/5755-30d102586789bf7f.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/5957.3f1a4012388dd962.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/5977-59fedea50d13c762.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/602.9bf02ac8e9502598.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/6020.3a1b347e2d2dfacc.js +0 -8
  689. package/apps/pwa/out/_next/static/chunks/6375.fce1d174ba6d0324.js +0 -64
  690. package/apps/pwa/out/_next/static/chunks/6546.92a828aef441271f.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/658.957fdb0a8c6c6c8e.js +0 -287
  692. package/apps/pwa/out/_next/static/chunks/6706.323590aabb8b1293.js +0 -226
  693. package/apps/pwa/out/_next/static/chunks/6747.b67947f293a4c02d.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/6868.000b24a3045c5574.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/6877-74399f69c7da1433.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/6946.bba74e9c96050f30.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/7033.a558f1b2f6912a53.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/7065.46029c26c53eac50.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/7087.6fae577d09249bc1.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/722.de8d9801e0f6d414.js +0 -41
  701. package/apps/pwa/out/_next/static/chunks/726.83532d69452ee24b.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +0 -1
  703. package/apps/pwa/out/_next/static/chunks/7497.57981e9d7a75a52a.js +0 -24
  704. package/apps/pwa/out/_next/static/chunks/7672.4af122ad892117c7.js +0 -1
  705. package/apps/pwa/out/_next/static/chunks/771.6ab889a233e7dae7.js +0 -1
  706. package/apps/pwa/out/_next/static/chunks/7797-df5aa0381fdc078f.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/8060-cc008cc6fedfa818.js +0 -1
  708. package/apps/pwa/out/_next/static/chunks/8085-d065d0393c1760f5.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/8096.f7da0776cfde6300.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/8401-35e94e9091f5eb8d.js +0 -1
  711. package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +0 -1
  712. package/apps/pwa/out/_next/static/chunks/8695-846034ce44852c70.js +0 -1
  713. package/apps/pwa/out/_next/static/chunks/8769.815ca69879f608b4.js +0 -104
  714. package/apps/pwa/out/_next/static/chunks/8857-f1762140ef9a96b1.js +0 -1
  715. package/apps/pwa/out/_next/static/chunks/8f835b4f.048eeb02299e3e12.js +0 -1
  716. package/apps/pwa/out/_next/static/chunks/9068.5f2764fccf86c1b2.js +0 -93
  717. package/apps/pwa/out/_next/static/chunks/9103-60fbef33e66f0a46.js +0 -1
  718. package/apps/pwa/out/_next/static/chunks/9247-7581825d511a64c0.js +0 -1
  719. package/apps/pwa/out/_next/static/chunks/935.4ddaa99fc1d1126c.js +0 -1
  720. package/apps/pwa/out/_next/static/chunks/9451.ebfb0dcc9c02250f.js +0 -23
  721. package/apps/pwa/out/_next/static/chunks/9497-b0e758d1cd4ae8d7.js +0 -1
  722. package/apps/pwa/out/_next/static/chunks/9559.e648369b1d57cf9a.js +0 -62
  723. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c1a96669158471ec.js +0 -1
  724. package/apps/pwa/out/_next/static/chunks/app/approvals/page-937c92292a4ab4f0.js +0 -1
  725. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-d781be3e3a9cfd74.js +0 -1
  726. package/apps/pwa/out/_next/static/chunks/app/board/page-b0a80997903852d8.js +0 -1
  727. package/apps/pwa/out/_next/static/chunks/app/botlab/page-2b1263165630d9c8.js +0 -1
  728. package/apps/pwa/out/_next/static/chunks/app/bots/page-ea998f7f5d156bea.js +0 -1
  729. package/apps/pwa/out/_next/static/chunks/app/ceo/page-33c328b64ca508f8.js +0 -1
  730. package/apps/pwa/out/_next/static/chunks/app/chat/page-e2d6bed48ac20120.js +0 -1
  731. package/apps/pwa/out/_next/static/chunks/app/control/page-544dd4bd4847eeb7.js +0 -1
  732. package/apps/pwa/out/_next/static/chunks/app/decisions/page-3ee191319bf97d87.js +0 -1
  733. package/apps/pwa/out/_next/static/chunks/app/design-check/page-e4bcb2c503dab04b.js +0 -1
  734. package/apps/pwa/out/_next/static/chunks/app/editor/page-300897dcbbd5ed76.js +0 -1
  735. package/apps/pwa/out/_next/static/chunks/app/exec/page-a449f1ed472b81c2.js +0 -1
  736. package/apps/pwa/out/_next/static/chunks/app/field/page-9045094d6d3b5cd0.js +0 -1
  737. package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +0 -1
  738. package/apps/pwa/out/_next/static/chunks/app/inside/page-c06673596849ef45.js +0 -1
  739. package/apps/pwa/out/_next/static/chunks/app/intake/page-103fa3191c1b2e08.js +0 -1
  740. package/apps/pwa/out/_next/static/chunks/app/layout-9f81233f29dcd409.js +0 -1
  741. package/apps/pwa/out/_next/static/chunks/app/live/page-be8b4615c919e36c.js +0 -1
  742. package/apps/pwa/out/_next/static/chunks/app/live-run/page-c685b104e0dfa609.js +0 -1
  743. package/apps/pwa/out/_next/static/chunks/app/loops/page-8d693331cfbb6add.js +0 -1
  744. package/apps/pwa/out/_next/static/chunks/app/market/page-cef4f30a4c22fae1.js +0 -1
  745. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66ea1b54fc83fa15.js +0 -1
  746. package/apps/pwa/out/_next/static/chunks/app/morning/page-7a12f61be4a579d1.js +0 -1
  747. package/apps/pwa/out/_next/static/chunks/app/not-found-c85b0589591a99c9.js +0 -1
  748. package/apps/pwa/out/_next/static/chunks/app/observatory/page-725a4da02dd129eb.js +0 -1
  749. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-8cc707bd09a497d9.js +0 -1
  750. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-90b55be1f15ce0e8.js +0 -1
  751. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-cb16606e08be65db.js +0 -1
  752. package/apps/pwa/out/_next/static/chunks/app/outputs/page-16dc64b74ed6a40a.js +0 -1
  753. package/apps/pwa/out/_next/static/chunks/app/page-21bec4afeb2f0917.js +0 -1
  754. package/apps/pwa/out/_next/static/chunks/app/reflection/page-dc39ee7a36d26385.js +0 -1
  755. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-84ae759f76053672.js +0 -1
  756. package/apps/pwa/out/_next/static/chunks/app/sessions/page-3db58ddb61fe2be9.js +0 -1
  757. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c5315e30f3528dc4.js +0 -1
  758. package/apps/pwa/out/_next/static/chunks/app/settings/page-2fe368efb6de3b6a.js +0 -1
  759. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8d04132dd0ac5e10.js +0 -1
  760. package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +0 -1
  761. package/apps/pwa/out/_next/static/chunks/app/setup/page-f23484de467c9ea3.js +0 -1
  762. package/apps/pwa/out/_next/static/chunks/app/share/page-c69762987b751174.js +0 -1
  763. package/apps/pwa/out/_next/static/chunks/app/showroom/page-5456692bda39aafb.js +0 -1
  764. package/apps/pwa/out/_next/static/chunks/app/tasks/page-d75f7cd65845ce98.js +0 -1
  765. package/apps/pwa/out/_next/static/chunks/app/term/page-5603f5e568b25ce3.js +0 -1
  766. package/apps/pwa/out/_next/static/chunks/app/today/page-d2cc0f4e89f42028.js +0 -1
  767. package/apps/pwa/out/_next/static/chunks/app/trace/page-a6eb73b8a4840f1c.js +0 -1
  768. package/apps/pwa/out/_next/static/chunks/app/vault/page-c0a3f4d10edb83fa.js +0 -1
  769. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-6c0b88068c143f15.js +0 -1
  770. package/apps/pwa/out/_next/static/chunks/app/workflows/page-7f8d7fcdf058a845.js +0 -1
  771. package/apps/pwa/out/_next/static/chunks/app/workspace/page-22163556cd38bc88.js +0 -1
  772. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-141436fd26dd56fc.js +0 -1
  773. package/apps/pwa/out/_next/static/chunks/f6231284-45726550aba08fca.js +0 -1
  774. package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +0 -1
  775. package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +0 -1
  776. package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +0 -1
  777. package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.js +0 -1
  778. package/apps/pwa/out/_next/static/chunks/webpack-f2b4016b9b981bc8.js +0 -1
  779. package/apps/pwa/out/_next/static/css/e81df11490b4413b.css +0 -1
  780. /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). Default `true`.
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
- try { args = acc.argsJson ? JSON.parse(acc.argsJson) : {}; } catch { /* empty */ }
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
- for await (const ev of parseOpenAISSELines(sseLineStream(response.body!))) {
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 claude-4 / claude-3.7 (extended thinking)
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
- // Extended thinking is GA on claude-3.7 onward — anything 4-family
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 = /-(\d+)(?:[-.](\d+))?$/.exec(m);
1932
- if (!v) return false;
1933
- const generation = Number(v[1]);
1934
- const minor = v[2] === undefined ? 0 : Number(v[2]);
1935
- if (generation >= 5) return true;
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
- export function toOpenAITools(tools: LLMToolSpec[] | undefined): any[] | undefined {
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: { name: t.name, description: t.description, parameters: strictifyToolSchema(t.parameters) },
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 (claude-3-7 / 4 family).
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 (supportsThinking) betas.push('interleaved-thinking-2025-05-14');
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
- type ObservedUsage = Pick<LLMUsage, 'inputTokens' | 'outputTokens' | 'cacheReadInputTokens' | 'cacheCreationInputTokens'>;
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 step: IteratorResult<string | LLMStreamEvent>;
4549
+ let idleTimer: ReturnType<typeof setTimeout> | undefined;
4550
+ let step: { idle: true } | { idle: false; result: IteratorResult<string | LLMStreamEvent> };
4464
4551
  try {
4465
- step = await iterator.next();
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) throw err;
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
- // ⭐ 세 갈래(codex · grok · local)가 «같은 모양의 if» 였다 — 해소 지점을 하나로 모은다.
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 finalText = finalizeVisibleAssistantText(
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 finalText = finalizeVisibleAssistantText(
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 tools = toOpenAITools(opts.tools);
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: messages.flatMap((m) => toOpenAIMessages(m, {
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
- { model: openRouterWireModel, headers: { 'X-Title': 'elanous' }, omitDefaultTemperature: true, omitMaxTokens: true, extraBody: { usage: { include: true } } },
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