elanous 0.2.22 → 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 (705) 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-80ed511e02c81412.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/{aBi6EyMtLsrl7J8eH4kF7 → 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/log-horizon/log-horizon-watch.yaml +25 -0
  288. package/graphs/log-horizon/recipes.yaml +3 -0
  289. package/graphs/release/recipes.yaml +1 -1
  290. package/graphs/release/release-loop.yaml +6 -2
  291. package/graphs/release-rehearsal/recipes.yaml +12 -0
  292. package/graphs/release-rehearsal/release-rehearsal.yaml +17 -0
  293. package/package.json +4 -1
  294. package/scripts/bench-report.ts +82 -3
  295. package/scripts/ci-typecheck-changed.ts +10 -1
  296. package/scripts/hq/hq-fence-wrapper.sh +148 -0
  297. package/scripts/lib/typecheck-ratchet.ts +51 -0
  298. package/scripts/openai-relay-server.ts +5 -1
  299. package/scripts/release-loop/docs-node.ts +258 -43
  300. package/scripts/release-loop/gate-method.ts +59 -0
  301. package/scripts/release-loop/gate-node.ts +73 -7
  302. package/scripts/release-loop/gate-wall.ts +208 -0
  303. package/scripts/release-loop/known-issues-node.ts +53 -8
  304. package/scripts/release-loop/publish-at.ts +14 -0
  305. package/scripts/release-loop/publish-node.ts +17 -2
  306. package/scripts/release-loop/resume-release.ts +34 -4
  307. package/scripts/release-loop/resume.ts +53 -0
  308. package/scripts/release-loop/shard-plan.ts +3 -11
  309. package/scripts/release-loop/tui-node-checks.ts +22 -0
  310. package/scripts/release-loop/unattended-release.ts +8 -1
  311. package/scripts/rhythm/daily.ts +51 -2
  312. package/scripts/rhythm/weekly.ts +3 -2
  313. package/scripts/tsc-main-safety-net.ts +189 -0
  314. package/scripts/usage-rollup.ts +8 -4
  315. package/src/acp/codex-plugins.ts +48 -6
  316. package/src/agent/monad-agent-turn.ts +67 -5
  317. package/src/agent/run-context.ts +10 -0
  318. package/src/agent/tool-profile.ts +28 -2
  319. package/src/agent-mission/acp-judge.ts +8 -2
  320. package/src/agent-mission/capabilities-cli.ts +16 -1
  321. package/src/agent-mission/driver.ts +1 -1
  322. package/src/agent-mission/pr-review-watch.ts +6 -2
  323. package/src/agent-mission/review-loop.ts +33 -5
  324. package/src/agent-substrate/acp-reviewer.ts +17 -8
  325. package/src/agent-substrate/pr-reviewer.ts +164 -28
  326. package/src/agent-substrate/review-intent.ts +6 -4
  327. package/src/agent-substrate/self-review-cli.ts +111 -16
  328. package/src/agent-substrate/shard-boundary-intent.ts +92 -26
  329. package/src/ask-user-question/pending-questions.ts +8 -2
  330. package/src/autopilot/build/llm-conflict-merge.ts +216 -12
  331. package/src/autopilot/codebase-grounding.ts +44 -0
  332. package/src/autopilot/llm-control-brain.ts +13 -1
  333. package/src/autopilot/mission-codebase-gate.ts +8 -77
  334. package/src/autopilot/pr-manager.ts +12 -3
  335. package/src/boot/acp-server.ts +4 -7
  336. package/src/boot/acp-socket-path.ts +7 -0
  337. package/src/briefing/brief-items.ts +21 -13
  338. package/src/chat/index.ts +12 -3
  339. package/src/cli/agent-cli.ts +20 -0
  340. package/src/cli/brief-cli.ts +27 -21
  341. package/src/cli/cli-user-error.ts +9 -2
  342. package/src/cli/log-event-names.ts +3 -0
  343. package/src/cli/logs-cli.ts +1 -0
  344. package/src/cli/mcp-login.ts +111 -37
  345. package/src/cli/plugin-cli.ts +21 -1
  346. package/src/cli/pod-cli.ts +26 -0
  347. package/src/cli/pr-cli.ts +30 -2
  348. package/src/cli/pr-land-overlap-evidence.ts +131 -0
  349. package/src/cli/release-cli.ts +53 -11
  350. package/src/cli/self-update.ts +173 -10
  351. package/src/cli/skills-cli.ts +12 -3
  352. package/src/cli/tasks-cli.ts +133 -27
  353. package/src/context-bus/context-first.ts +51 -2
  354. package/src/context-bus/context-now-surfaces.ts +13 -2
  355. package/src/context-bus/long-term-memory.ts +3 -1
  356. package/src/context-bus/nightly-condense.ts +3 -2
  357. package/src/core-turn/run-goal-loop.ts +86 -2
  358. package/src/dashboard/chat-fold.ts +20 -0
  359. package/src/dashboard/first-screen-band.ts +151 -1
  360. package/src/dashboard/index.ts +27 -5
  361. package/src/dashboard/slash-runtime/dashboard-handlers.ts +5 -3
  362. package/src/dashboard/stale-install-check.ts +13 -2
  363. package/src/dashboard/turn-stream-formatter.ts +25 -0
  364. package/src/debug/log-diet.ts +159 -0
  365. package/src/debug/log.ts +52 -17
  366. package/src/display/coordinator.ts +25 -2
  367. package/src/domains/coo-admin-tool.ts +27 -0
  368. package/src/domains/cron-match.ts +1 -0
  369. package/src/domains/outbound-alert.ts +17 -6
  370. package/src/domains/release-tool.ts +119 -10
  371. package/src/domains/schedule-registry.ts +10 -7
  372. package/src/domains/schedule-runner.ts +1 -0
  373. package/src/elanous-config-dir.ts +2 -2
  374. package/src/elanous-daemon.ts +3 -3
  375. package/src/execution-loop/launch-gate.ts +1 -1
  376. package/src/expression/i18n/messages.en.ts +5 -0
  377. package/src/expression/i18n/messages.ja.ts +5 -0
  378. package/src/expression/i18n/messages.ko.ts +5 -0
  379. package/src/expression/i18n/messages.zh.ts +5 -0
  380. package/src/expression/i18n/types.ts +8 -0
  381. package/src/github/pr-labels.ts +1 -0
  382. package/src/graph-runner/runner.ts +54 -5
  383. package/src/harness/dispatch-backpressure.ts +259 -0
  384. package/src/harness/harness-cli-command.ts +107 -28
  385. package/src/harness/harness-seams.ts +2 -20
  386. package/src/harness/harness-substrate-default.ts +72 -1
  387. package/src/harness/nested-elanous-policy.ts +4 -2
  388. package/src/hq/fence-wrapper.ts +7 -0
  389. package/src/hq/hq.ts +33 -2
  390. package/src/hq/lease.ts +13 -0
  391. package/src/hq/seats.ts +114 -18
  392. package/src/index.ts +163 -64
  393. package/src/intake-plane/collect-github.ts +19 -1
  394. package/src/intake-plane/digest.ts +45 -20
  395. package/src/intake-plane/lens.ts +36 -8
  396. package/src/intelligence-map/model-alias.ts +6 -0
  397. package/src/intelligence-map/model-catalog.ts +41 -0
  398. package/src/knowledge/kgs/pack.ts +5 -2
  399. package/src/knowledge/kgs/sqlite-store.ts +15 -0
  400. package/src/knowledge/tools/knowledge-query.ts +20 -2
  401. package/src/knowledge/write.ts +234 -2
  402. package/src/llm/bedrock-provider.ts +175 -0
  403. package/src/llm/bedrock.ts +345 -0
  404. package/src/llm/provider-credentials.ts +3 -1
  405. package/src/llm.ts +306 -35
  406. package/src/loops/budget.ts +150 -0
  407. package/src/loops/orchestrator/seat-share.ts +6 -49
  408. package/src/loops/orchestrator/traffic.ts +5 -81
  409. package/src/market/signed-index.ts +42 -0
  410. package/src/mcp/mcp-oauth.ts +136 -17
  411. package/src/model-tier/llm-tier-map.ts +48 -4
  412. package/src/models/prompts.ts +22 -1
  413. package/src/mss/logging/horizon-watch.ts +168 -0
  414. package/src/mss/logging/log-store.ts +204 -15
  415. package/src/native-tool-catalog.ts +1 -1
  416. package/src/nexus/api/consult-requests.ts +7 -10
  417. package/src/nexus/api/discord-trigger-bot.ts +6 -3
  418. package/src/nexus/api/error-reports.ts +30 -8
  419. package/src/nexus/api/http-server.ts +8 -0
  420. package/src/nexus/api/loop-resources.ts +42 -0
  421. package/src/nexus/api/outbound-report.ts +8 -3
  422. package/src/nexus/api/telegram-trigger-bot.ts +6 -3
  423. package/src/nexus/index.ts +10 -0
  424. package/src/nexus/outbound/format.ts +2 -0
  425. package/src/nexus/outbound/router.ts +198 -13
  426. package/src/oauth/codex-account-rotation.ts +16 -18
  427. package/src/oauth/codex-account-store.ts +134 -5
  428. package/src/oauth/fallback-chain.ts +28 -6
  429. package/src/onboarding.ts +2 -1
  430. package/src/plugins/adapters/claude-package.ts +4 -12
  431. package/src/plugins/core/capability-policy.ts +141 -0
  432. package/src/plugins/core/host.ts +21 -8
  433. package/src/plugins/core/manifest.ts +19 -2
  434. package/src/plugins/core/trust-store.ts +15 -0
  435. package/src/plugins/core/types.ts +12 -0
  436. package/src/plugins/install/market-fetch.ts +68 -16
  437. package/src/plugins/install/plugin-install.ts +187 -16
  438. package/src/plugins/maker/plugin-maker.ts +25 -20
  439. package/src/plugins/maker/wizard-generate.ts +16 -2
  440. package/src/policy/llm-policy.ts +14 -1
  441. package/src/process/pid-liveness.ts +1 -1
  442. package/src/prompt-cache/openai.ts +10 -6
  443. package/src/prompt-cache/openrouter.ts +94 -0
  444. package/src/prompt-enhance/enhance.ts +46 -5
  445. package/src/prompt-library/family-prompt-coverage.ts +1 -0
  446. package/src/prompt-library/universal-preamble.ts +2 -2
  447. package/src/registry/discovery/openrouter-live-resolve.ts +122 -0
  448. package/src/registry/loader.ts +6 -1
  449. package/src/release-loop/checklist.ts +24 -9
  450. package/src/release-loop/feature-store.ts +3 -0
  451. package/src/release-loop/gate-shards.ts +48 -4
  452. package/src/release-loop/landed-to-green.ts +81 -0
  453. package/src/release-loop/light-rc.ts +11 -1
  454. package/src/release-loop/merged-pr-checklist.ts +10 -0
  455. package/src/release-loop/placement.ts +91 -22
  456. package/src/release-loop/rehearsal.ts +317 -0
  457. package/src/release-loop/release-schedule.ts +13 -1
  458. package/src/release-loop/rubric-types.ts +1 -0
  459. package/src/release-loop/rubric.ts +2 -2
  460. package/src/retro/daily.ts +23 -9
  461. package/src/seat-loop/seat-loop.ts +34 -1
  462. package/src/seat-loop/traffic-signal.ts +44 -0
  463. package/src/self-dev/ask-launch-flow.ts +2 -2
  464. package/src/self-dev/dev-cli.ts +67 -3
  465. package/src/self-dev/dev-pipeline.ts +4 -6
  466. package/src/self-dev/draft-residue.ts +463 -0
  467. package/src/self-dev/draft-sweep.ts +151 -10
  468. package/src/self-dev/draft-triage-rules.ts +27 -1
  469. package/src/self-dev/launch-preflight-text.ts +549 -0
  470. package/src/self-dev/launch-preflight.ts +10 -545
  471. package/src/self-dev/orchestrate-cli.ts +57 -2
  472. package/src/self-dev/orchestrate-summary-line.ts +13 -0
  473. package/src/self-dev/orchestrate.ts +8 -135
  474. package/src/self-dev/review-provider-fallback.ts +115 -19
  475. package/src/self-dev/run-store.ts +1 -3
  476. package/src/self-dev/run-supervisor.ts +3 -22
  477. package/src/self-dev/run-types.ts +178 -0
  478. package/src/self-dev/shard-aggregate.ts +61 -13
  479. package/src/self-dev/shard-plan.ts +5 -1
  480. package/src/self-dev/shard-run.ts +23 -5
  481. package/src/self-dev/supervisor-verdict-edges.ts +2 -4
  482. package/src/self-implement/blocked-draft-policy.ts +3 -19
  483. package/src/self-implement/draft-on-stop-mode.ts +18 -0
  484. package/src/self-implement/follow-up-goals.ts +114 -38
  485. package/src/self-implement/gate-baseline-reap.ts +157 -0
  486. package/src/self-implement/gate-baseline.ts +78 -16
  487. package/src/self-implement/gate-cli.ts +12 -2
  488. package/src/self-implement/gate-remote.ts +17 -6
  489. package/src/self-implement/goal-author.ts +24 -4
  490. package/src/self-implement/goal-digest.ts +19 -0
  491. package/src/self-implement/graph-overlay-condition.ts +4 -0
  492. package/src/self-implement/headless-elanous-driver.ts +11 -9
  493. package/src/self-implement/host-regate.ts +120 -29
  494. package/src/self-implement/l8-merge-queue.ts +67 -5
  495. package/src/self-implement/merge-train.ts +131 -0
  496. package/src/self-implement/off-diff-evidence.ts +9 -0
  497. package/src/self-implement/orchestrator.ts +133 -16
  498. package/src/self-implement/review-finding-recurrence.ts +28 -0
  499. package/src/self-implement/rework-policy.ts +2 -1
  500. package/src/self-implement/round-summary-card.ts +63 -0
  501. package/src/self-implement/run-ledger.ts +4 -3
  502. package/src/self-implement/run-step-projection.ts +147 -0
  503. package/src/self-implement/run-stop.ts +1 -1
  504. package/src/self-implement/seams.ts +36 -3
  505. package/src/self-implement/self-implement-cli.ts +3 -1
  506. package/src/self-implement/train-gate-remote.ts +158 -0
  507. package/src/session-runtime/index.ts +10 -1
  508. package/src/session-runtime/retry-api.ts +11 -1
  509. package/src/skills/gift-install.ts +119 -0
  510. package/src/skills/runner.ts +59 -2
  511. package/src/skills/skill-feedback.ts +31 -1
  512. package/src/skills/skill-tier.ts +1 -0
  513. package/src/smart-wizard/capability-index.ts +231 -0
  514. package/src/smart-wizard/rung.ts +74 -0
  515. package/src/steward/launch.ts +20 -9
  516. package/src/steward/triage.ts +4 -2
  517. package/src/storage/file-lock.ts +8 -1
  518. package/src/task-agent/actions.ts +4 -0
  519. package/src/task-agent/card-evidence.ts +59 -13
  520. package/src/task-agent/judge.ts +4 -3
  521. package/src/task-agent/land-worktree.ts +201 -0
  522. package/src/task-agent/live-move-history.ts +133 -0
  523. package/src/task-agent/live-moves.ts +106 -19
  524. package/src/task-agent/parent-host.ts +117 -8
  525. package/src/task-agent/rejudge-on-head.ts +297 -0
  526. package/src/task-agent/review-result-capture.ts +218 -0
  527. package/src/task-agent/shadow.ts +103 -7
  528. package/src/task-agent/task-hand.ts +136 -11
  529. package/src/task-orchestrator/surfaces/pod-child-providers.ts +29 -0
  530. package/src/task-orchestrator/surfaces/pod-command-job.ts +6 -3
  531. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +16 -2
  532. package/src/task-orchestrator/surfaces/pod-image-source.ts +212 -0
  533. package/src/task-orchestrator/surfaces/pod-lease.ts +93 -12
  534. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +25 -2
  535. package/src/task-orchestrator/surfaces/pod-pool.ts +66 -14
  536. package/src/task-orchestrator/surfaces/self-implement-pod.ts +259 -36
  537. package/src/task-orchestrator/surfaces/self-implement.ts +6 -2
  538. package/src/telegram-service.ts +5 -1
  539. package/src/telegram.ts +17 -4
  540. package/src/time/format.ts +13 -4
  541. package/src/tool-runtime/goal-author-runtime.ts +1 -0
  542. package/src/tool-runtime/self-cognition-catalog.ts +23 -0
  543. package/src/tool-runtime/self-cognition-runtimes.ts +2 -24
  544. package/src/user-config.ts +132 -24
  545. package/src/ux-sim/slash-menu-frames.ts +168 -0
  546. package/src/version/packed-revision.json +1 -1
  547. package/src/web-terminal/preview-tap-registry.ts +5 -2
  548. package/src/workflow-runtime/triggers/scheduler.ts +1 -0
  549. package/apps/pwa/out/_next/static/chunks/1109.78a7a3288c0259d9.js +0 -148
  550. package/apps/pwa/out/_next/static/chunks/115.1c6690b8604f81c4.js +0 -32
  551. package/apps/pwa/out/_next/static/chunks/1262.76a3f08e67c5f816.js +0 -309
  552. package/apps/pwa/out/_next/static/chunks/1307-08b716476f1d50af.js +0 -1
  553. package/apps/pwa/out/_next/static/chunks/1358d292.5c87f12cad6eaa91.js +0 -122
  554. package/apps/pwa/out/_next/static/chunks/1438.27a1a7b8f2308004.js +0 -149
  555. package/apps/pwa/out/_next/static/chunks/1442.02d85cd88f4c1eac.js +0 -79
  556. package/apps/pwa/out/_next/static/chunks/1501-1aad662d82ba43f7.js +0 -1
  557. package/apps/pwa/out/_next/static/chunks/1584.9e2dd53da6e6d4b1.js +0 -24
  558. package/apps/pwa/out/_next/static/chunks/1586.b989b0614afb77e6.js +0 -1
  559. package/apps/pwa/out/_next/static/chunks/1609.2ad355062870151f.js +0 -1
  560. package/apps/pwa/out/_next/static/chunks/1612-f6df0fc0eed7157b.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/1826-5d279da64bbbc2de.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/1923.37f1d5fe7ebe3860.js +0 -27
  563. package/apps/pwa/out/_next/static/chunks/195-fb1d7690bf30bab4.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/1986-33e13d648a9df765.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/1993.3fd074a2a246234e.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/211-9c9090c59e2c5907.js +0 -1
  567. package/apps/pwa/out/_next/static/chunks/2140.d2daf9ee96e295d1.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/2212.0359851457473efc.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/224.583e562365a52f74.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/2328.0f37465646bafa7d.js +0 -36
  572. package/apps/pwa/out/_next/static/chunks/2372.bf71372184991937.js +0 -286
  573. package/apps/pwa/out/_next/static/chunks/2489-d238d3e2eb5b2bf5.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/2537-6c289376caa88ca1.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/2549-a8515c86f9e8cb96.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/2655.72cc6a97276c5acc.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/2699-325cc923ba7b8631.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/2743-ef6e8c3ced74cce5.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/2840-5458ad50c49cac6a.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/2856.f75d5baef7f49b74.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/311.e685738f92e6e2ec.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/3344.0de4b0ec5a454b7a.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/335.a13f339e97893437.js +0 -94
  586. package/apps/pwa/out/_next/static/chunks/3394.646348f34b2500be.js +0 -1
  587. package/apps/pwa/out/_next/static/chunks/3443.6276909b53d72d53.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/3495.abd4254d808bf2dc.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/3558-bbb5ab553a0471d3.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/3721.ba5b82db0d9a5572.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/3857-5985236d9307f676.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/3919.9ff7dc25afefee33.js +0 -74
  594. package/apps/pwa/out/_next/static/chunks/3998.bd9a69d9b50e9bd2.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/4003.ab6db1dc266576c9.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/4144-fad095b48a1862ee.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/4216.e8ac94b9fe6b96ab.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/4327.c44dc2b55cb43ee5.js +0 -34
  599. package/apps/pwa/out/_next/static/chunks/4401.94257d497b6d26bc.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/4559.17ca2cdbaa8d414f.js +0 -115
  601. package/apps/pwa/out/_next/static/chunks/4565-3d7e3fdeb43686a8.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/4706.97e734bd4c9816ca.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/4795-f372490b178583fc.js +0 -1
  604. package/apps/pwa/out/_next/static/chunks/4982.6e44352f751b9a1b.js +0 -77
  605. package/apps/pwa/out/_next/static/chunks/5342.49c5c5a530e62b50.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/5360-08a80abdf3a4da99.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/5431.66c58ab1327ee0b7.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/5633-d6852385000738ef.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/5717.bcfcb96e701b82e0.js +0 -90
  610. package/apps/pwa/out/_next/static/chunks/5755-30d102586789bf7f.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/5957.3f1a4012388dd962.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/5977-5b9e8a45a5b0c823.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/602.9bf02ac8e9502598.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/6020.3a1b347e2d2dfacc.js +0 -8
  615. package/apps/pwa/out/_next/static/chunks/6375.fce1d174ba6d0324.js +0 -64
  616. package/apps/pwa/out/_next/static/chunks/6546.92a828aef441271f.js +0 -1
  617. package/apps/pwa/out/_next/static/chunks/658.957fdb0a8c6c6c8e.js +0 -287
  618. package/apps/pwa/out/_next/static/chunks/6706.323590aabb8b1293.js +0 -226
  619. package/apps/pwa/out/_next/static/chunks/6747.b67947f293a4c02d.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/6868.000b24a3045c5574.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/6877-74399f69c7da1433.js +0 -1
  622. package/apps/pwa/out/_next/static/chunks/6946.bba74e9c96050f30.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/7033.a558f1b2f6912a53.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/7065.46029c26c53eac50.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/7087.6fae577d09249bc1.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/722.de8d9801e0f6d414.js +0 -41
  627. package/apps/pwa/out/_next/static/chunks/726.83532d69452ee24b.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/7497.57981e9d7a75a52a.js +0 -24
  630. package/apps/pwa/out/_next/static/chunks/7672.4af122ad892117c7.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/771.6ab889a233e7dae7.js +0 -1
  632. package/apps/pwa/out/_next/static/chunks/7797-df5aa0381fdc078f.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/8060-cc008cc6fedfa818.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/8085-d065d0393c1760f5.js +0 -1
  635. package/apps/pwa/out/_next/static/chunks/8096.f7da0776cfde6300.js +0 -1
  636. package/apps/pwa/out/_next/static/chunks/8401-35e94e9091f5eb8d.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/8695-846034ce44852c70.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/8769.815ca69879f608b4.js +0 -104
  640. package/apps/pwa/out/_next/static/chunks/8857-aa1cc4ac90af4d40.js +0 -1
  641. package/apps/pwa/out/_next/static/chunks/8f835b4f.048eeb02299e3e12.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/9068.5f2764fccf86c1b2.js +0 -93
  643. package/apps/pwa/out/_next/static/chunks/9103-60fbef33e66f0a46.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/9247-55bcfbb0e8057f59.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/935.4ddaa99fc1d1126c.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/9451.ebfb0dcc9c02250f.js +0 -23
  647. package/apps/pwa/out/_next/static/chunks/9559.e648369b1d57cf9a.js +0 -62
  648. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c1a96669158471ec.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/app/approvals/page-88459e0903da2803.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-d85c43f46f58716b.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/app/board/page-4e645600579ae952.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/app/botlab/page-87edbfd19117823b.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/app/bots/page-7f0c2b7801ac6a54.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/app/ceo/page-bf1f030a9d1adffd.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/app/chat/page-cbaf66b1e1804adf.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/app/control/page-9f5610caaa06178c.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/app/decisions/page-ec8f3575e339de74.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/app/design-check/page-86d753e460f1a989.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/app/editor/page-4166a7d51cf0a57d.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/app/exec/page-2a19c5cd3b562580.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/app/field/page-b6a09cde2e07521a.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/app/inside/page-f7eae1518ca0c353.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/app/intake/page-456a8573ad811381.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/app/layout-8462d6a543cbb2d9.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/app/live/page-2974cdfb87c0f9c9.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/app/live-run/page-f927ffa25f3c86d1.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/app/loops/page-abd86cd832aaa011.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/app/market/page-79daf68f6256adaa.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-8c3f168fc3f91939.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/app/morning/page-786fb4504d0f2fa9.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/app/not-found-75209f14597dcb8f.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/app/observatory/page-bf30affe3a85af7e.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1187a44b7515434b.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-3d0910185a66ed54.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-f401ee1dd5a26e25.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/app/outputs/page-5dfe7604fd842784.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/app/page-76cf838050a8d681.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/app/reflection/page-7ec8e289b4c14df6.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-8c8ac17d52be2a79.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/app/sessions/page-d359ab048d63a9d9.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-b8b345c880bf78d1.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/app/settings/page-f151cc10ad026940.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-9875f103057da433.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/app/setup/page-9789328af9a9aa62.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/app/share/page-bf495a1e284f4e00.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/app/showroom/page-a263d94bca4be22a.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/app/tasks/page-3962eab8ec58d16e.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/app/term/page-9abcfac07e02a542.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/app/today/page-bee49f927c333abb.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/app/trace/page-bac2d56dcb02d955.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/app/vault/page-937cbcc13176295c.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-d09495594f7f480d.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/app/workflows/page-69cb93d1a2e57e0e.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/app/workspace/page-72ec543928d67c3e.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-82906eeda0186a7b.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/f6231284-45726550aba08fca.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.js +0 -1
  703. package/apps/pwa/out/_next/static/chunks/webpack-f2b4016b9b981bc8.js +0 -1
  704. package/apps/pwa/out/_next/static/css/f2bd5257e6af88d8.css +0 -1
  705. /package/apps/pwa/out/_next/static/{aBi6EyMtLsrl7J8eH4kF7 → 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;
@@ -2420,12 +2467,29 @@ export function dedupeToolsByName(tools: LLMToolSpec[] | undefined): LLMToolSpec
2420
2467
  return out.length === tools.length ? tools : out;
2421
2468
  }
2422
2469
 
2423
- 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 {
2424
2483
  const unique = dedupeToolsByName(tools);
2425
2484
  if (!unique || unique.length === 0) return undefined;
2426
2485
  return unique.map(t => ({
2427
2486
  type: 'function',
2428
- 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
+ },
2429
2493
  }));
2430
2494
  }
2431
2495
 
@@ -3904,6 +3968,7 @@ export const PROVIDERS: Record<string, LLMProvider> = {
3904
3968
  streamChat: (messages, opts = {}) => makeOpenRouterProvider({ provider: 'openrouter' }).streamChat!(messages, opts),
3905
3969
  chat: (messages, opts = {}) => makeOpenRouterProvider({ provider: 'openrouter' }).chat!(messages, opts),
3906
3970
  },
3971
+ bedrock: BedrockProvider, // 명시 선택 전용 — 자동 순서·폴백 체인에 «안» 넣는다(src/llm/bedrock-provider.ts)
3907
3972
  };
3908
3973
 
3909
3974
  const AUTOMATIC_PROVIDER_ORDER = ['grok', 'anthropic', 'gemini', 'local'] as const;
@@ -4085,12 +4150,13 @@ export function decideProviderForConfig(
4085
4150
  return { provider, model: selectedModel, auth: baseUrl || getLocalLLMUrl() ? 'local' : 'none' };
4086
4151
  case 'openrouter':
4087
4152
  return { provider, model: selectedModel, auth: apiKey || getOpenRouterApiKey() ? 'apikey' : 'none' };
4153
+ case 'bedrock': return { provider, model: selectedModel, auth: authKindForProvider('bedrock', selectedModel) };
4088
4154
  }
4089
4155
  throw new Error(`unknown provider: ${provider as string}`);
4090
4156
  }
4091
4157
 
4092
4158
  function isKnownProviderName(provider: string): provider is ConcreteProviderName {
4093
- 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';
4094
4160
  }
4095
4161
 
4096
4162
  function authKindForProvider(provider: string, model: string, apiKey?: string): ProviderDecisionAuth {
@@ -4105,6 +4171,7 @@ function authKindForProvider(provider: string, model: string, apiKey?: string):
4105
4171
  if (provider === 'anthropic') return getAnthropicApiKey() ? 'apikey' : 'none';
4106
4172
  if (provider === 'gemini') return getGeminiApiKey() ? 'apikey' : 'none';
4107
4173
  if (provider === 'openrouter') return getOpenRouterApiKey() ? 'apikey' : 'none';
4174
+ if (provider === 'bedrock') return BedrockProvider.available() ? 'apikey' : 'none';
4108
4175
  if (provider === 'openai-codex') {
4109
4176
  try {
4110
4177
  return codexOAuthAvailable() ? 'oauth' : 'none';
@@ -4124,6 +4191,7 @@ function defaultModelForProvider(provider: ConcreteProviderName): string {
4124
4191
  case 'gemini': return GEMINI_MODEL;
4125
4192
  case 'local': return LOCAL_LLM_MODEL;
4126
4193
  case 'openrouter': return OPENROUTER_MODEL;
4194
+ case 'bedrock': return BedrockProvider.defaultModel;
4127
4195
  }
4128
4196
  throw new Error(`unknown provider: ${provider as string}`);
4129
4197
  }
@@ -4247,7 +4315,7 @@ export function getProvider(model?: string): LLMProvider {
4247
4315
  if (adapted && PROVIDERS[adapted]) return PROVIDERS[adapted]!;
4248
4316
  // Unknown prefix — look up by exact name match on defaults
4249
4317
  for (const p of Object.values(PROVIDERS)) {
4250
- if (p.defaultModel === resolved) return p;
4318
+ if (p.name !== 'bedrock' && p.defaultModel === resolved) return p; // bedrock 은 명시 선택 전용
4251
4319
  }
4252
4320
  }
4253
4321
 
@@ -4374,6 +4442,7 @@ export function buildMessagesWithContext(
4374
4442
 
4375
4443
  // Re-export converters so tests/adapters can assert wire-format correctness.
4376
4444
  export { toOpenAIMessage, toOpenAIMessages, toAnthropicMessage, systemToAnthropicString };
4445
+ export { usesAdaptiveThinking, mapReasoningLevelToAnthropicThinking, mapReasoningLevelToAnthropicEffort, sseLineStream, retryOptsFor }; // src/llm/bedrock-provider.ts
4377
4446
 
4378
4447
  /**
4379
4448
  * Best-effort classification of whether a model accepts image inputs.
@@ -4430,7 +4499,10 @@ export function isLikelyVisionModel(model: string | undefined): boolean {
4430
4499
  * Convenience wrapper — stream chunks via a callback, returning the full text.
4431
4500
  * Mirrors the existing `streamGrok()` signature in chat.ts for drop-in use.
4432
4501
  */
4433
- 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'>;
4434
4506
 
4435
4507
  type ProviderTextResult =
4436
4508
  | { ok: true; full: string; usage: ObservedUsage | 'unmeasured' }
@@ -4438,7 +4510,7 @@ type ProviderTextResult =
4438
4510
 
4439
4511
  function accumulateUsage(usage: ObservedUsage | undefined, received: LLMUsage): ObservedUsage {
4440
4512
  const total = { ...usage };
4441
- for (const field of ['inputTokens', 'outputTokens', 'cacheReadInputTokens', 'cacheCreationInputTokens'] as const) {
4513
+ for (const field of ['inputTokens', 'outputTokens', 'cacheReadInputTokens', 'cacheCreationInputTokens', 'reportedCostUsd'] as const) {
4442
4514
  if (received[field] !== undefined) total[field] = (total[field] ?? 0) + received[field];
4443
4515
  }
4444
4516
  return total;
@@ -4468,17 +4540,40 @@ async function consumeProviderText(
4468
4540
  // Preserve the provider or callback error that caused this close.
4469
4541
  }
4470
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
+ );
4471
4547
 
4472
4548
  while (true) {
4473
- let step: IteratorResult<string | LLMStreamEvent>;
4549
+ let idleTimer: ReturnType<typeof setTimeout> | undefined;
4550
+ let step: { idle: true } | { idle: false; result: IteratorResult<string | LLMStreamEvent> };
4474
4551
  try {
4475
- 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
+ ]);
4476
4558
  } catch (error) {
4477
4559
  await closeIterator();
4478
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 };
4479
4574
  }
4480
- if (step.done) return { ok: true, full, usage: usage ?? 'unmeasured' };
4481
- 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;
4482
4577
  if (event.type === 'usage') {
4483
4578
  usage = accumulateUsage(usage, event.usage);
4484
4579
  try {
@@ -4504,11 +4599,11 @@ export async function streamLLM(
4504
4599
  onChunk: (delta: string, full: string) => void,
4505
4600
  opts: LLMOpts & { provider?: LLMProvider; initialProvider?: LLMProvider; onResolvedProvider?: (provider: string, model: string) => void } = {},
4506
4601
  ): Promise<string> {
4602
+ const started = Date.now();
4507
4603
  let activeProvider = opts.provider ?? opts.initialProvider ?? resolveDefaultProvider(opts.model);
4508
4604
  const attemptedProviders = new Set<string>([activeProvider.name]);
4509
4605
  let blockedProviders: ProviderFallbackAttempt[] = [];
4510
4606
  let modelOverride = opts.model;
4511
- const started = Date.now();
4512
4607
 
4513
4608
  while (true) {
4514
4609
  const finalized = finalizeStreamingProviderModel(
@@ -4527,6 +4622,7 @@ export async function streamLLM(
4527
4622
  maxTokens: opts.maxTokens,
4528
4623
  temperature: opts.temperature,
4529
4624
  }, { level: 'info' });
4625
+ // Keep text-only stream failures on streamLLM's existing provider fallback path.
4530
4626
  const consumed = await consumeProviderText(
4531
4627
  activeProvider,
4532
4628
  messages,
@@ -4544,6 +4640,7 @@ export async function streamLLM(
4544
4640
  logAgentTurnUsage(activeModel, consumed.usage, { providerName: activeProvider.name, site: 'stream-llm', role: opts.usageRole });
4545
4641
  } catch { /* best-effort observation */ }
4546
4642
  }
4643
+ debug.log('llm', 'outcome', { provider: activeProvider.name, status: 'ok', kind: 'streamLLM', durationMs: Date.now() - started });
4547
4644
  debug.log('llm.router.done', 'streamLLM', {
4548
4645
  provider: activeProvider.name,
4549
4646
  model: activeModel,
@@ -4579,7 +4676,10 @@ export async function streamLLM(
4579
4676
  message: reason,
4580
4677
  ...(isAuthRejectionError(err) ? { authRejected: true } : {}),
4581
4678
  }, { level: 'error' });
4582
- 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
+ }
4583
4683
  const remaining = remainingFallbackProviderNames(attemptedProviders, opts);
4584
4684
  const verdict = decideProviderFallback({
4585
4685
  err,
@@ -4604,6 +4704,7 @@ export async function streamLLM(
4604
4704
  continue;
4605
4705
  }
4606
4706
  if (verdict.action === 'stop') {
4707
+ debug.log('llm', 'outcome', { provider: activeProvider.name, status: 'error', kind: 'streamLLM', durationMs: Date.now() - started });
4607
4708
  debug.log('llm.router', 'provider-fallback-stop', {
4608
4709
  blockedProviders,
4609
4710
  category: verdict.category,
@@ -4622,6 +4723,7 @@ export async function streamLLM(
4622
4723
  ...(fallback ? { skippedFallbackProvider: fallback.name, emittedChars: full.length } : {}),
4623
4724
  }, { level: 'error' });
4624
4725
  onChunk(finalDelta, finalText);
4726
+ debug.log('llm', 'outcome', { provider: activeProvider.name, status: 'fallback-exhausted', kind: 'streamLLM', durationMs: Date.now() - started });
4625
4727
  return finalText;
4626
4728
  }
4627
4729
  }
@@ -5019,6 +5121,15 @@ const LOCAL_TOOL_DISCIPLINE = [
5019
5121
  '- 범위 읽기만으로 판단할 수 없을 때에만 전체 읽기를 선택하고, 읽은 뒤에는 다음 행동을 계속 결정하라.',
5020
5122
  ].join('\n');
5021
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
+
5022
5133
  /** 모델군 → 그 군에 주입할 툴 규율(없으면 `null`). **능력 술어 판** — 2026-08-14.
5023
5134
  *
5024
5135
  * ⛔ **왜 `if` 세 개가 아니라 이 표인가**: codex·grok·local 이 각각 「같은 모양의 if」로 붙어 있었고,
@@ -5040,6 +5151,7 @@ const TOOL_DISCIPLINE_BY_FAMILY: Record<ModelFamily, string | null> = {
5040
5151
  codex: CODEX_TOOL_DISCIPLINE,
5041
5152
  grok: GROK_TOOL_DISCIPLINE,
5042
5153
  local: LOCAL_TOOL_DISCIPLINE,
5154
+ 'open-weight': OPEN_WEIGHT_TOOL_DISCIPLINE,
5043
5155
  // ⬇ 아래 넷은 「아직 안 쟀다」이지 「필요 없다」가 아니다.
5044
5156
  // `other` 가 0인 것은 ***아무도 other 를 안 쟀기 때문***이고, 실제 자식 하나가 오늘 `other` 였다(`[S]` 실측).
5045
5157
  claude: null,
@@ -5217,6 +5329,19 @@ function appendFinalSynthesisNotice(existingText: string, notice: string): strin
5217
5329
  return existingText.length > 0 ? `${existingText}\n\n${notice}` : notice;
5218
5330
  }
5219
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
+
5220
5345
  function buildNoFinalSynthesisNotice(reason: 'empty-turn' | 'budget-exhausted'): string {
5221
5346
  const why = reason === 'empty-turn'
5222
5347
  ? 'The model stopped after repeated empty turns.'
@@ -7744,6 +7869,7 @@ export function selectIntentClassificationMessages(messages: readonly LLMMessage
7744
7869
  message.content === CODEX_TOOL_DISCIPLINE
7745
7870
  || message.content === GROK_TOOL_DISCIPLINE
7746
7871
  || message.content === LOCAL_TOOL_DISCIPLINE
7872
+ || message.content === OPEN_WEIGHT_TOOL_DISCIPLINE
7747
7873
  )
7748
7874
  ));
7749
7875
  }
@@ -7956,12 +8082,13 @@ export async function streamLLMWithTools(
7956
8082
  // the caller — no per-turn duplication when the caller persists new messages.
7957
8083
  // Adapters fold multiple system messages, so this composes with (does not
7958
8084
  // mutate) the caller's persona/system prompt.
7959
- // ⭐ 세 갈래(codex · grok · local)가 «같은 모양의 if» 였다 — 해소 지점을 하나로 모은다.
8085
+ // ⭐ 각 모델군의 규율은 같은 해소 지점에서 선택한다.
7960
8086
  // 대표 2026-08-14: *"claude 제외 다른 LLM 들이 공용화가 많아 보이고, 오히려 claude 일 때
7961
8087
  // 옵션화를 해야 하는 게 아닌지"* ⊕ `[S]` 와 합의한 축 분담(축② = 능력 술어는 `[T]` 소유).
7962
- // ⛔ 동작은 «바이트 하나» 안 바뀐다 — 같은 조건에 같은 문면이다(테스트가 전송분으로 문다).
8088
+ // ⛔ 기존 군의 문면은 «바이트 하나» 안 바뀐다(테스트가 전송분으로 문다).
7963
8089
  const toolDiscipline = resolveToolDiscipline(modelFamily);
7964
8090
  if (toolDiscipline !== null) {
8091
+ debug.log('llm.tool-discipline', 'injected', { modelFamily, model: effectiveModel, chars: toolDiscipline.length });
7965
8092
  // ⛔ **상수를 «그대로» 싣는다 — 합성하지 마라.**
7966
8093
  // `selectIntentClassificationMessages` 가 «정확 일치»로 이 메시지를 걸러 내므로,
7967
8094
  // 여기서 한 글자라도 덧붙이면 ***분류기 셋이 다시 «오염»된다***(그 함수 주석에 실측이 있다).
@@ -8305,6 +8432,7 @@ export async function streamLLMWithTools(
8305
8432
  name: string;
8306
8433
  args: Record<string, unknown>;
8307
8434
  providerMeta?: ProviderToolMeta;
8435
+ argsInvalid?: ToolArgsInvalid;
8308
8436
  }> = [];
8309
8437
  const turnStartedAt = Date.now();
8310
8438
  debug.log('llm.router', 'tool-loop.turn.start', {
@@ -8520,6 +8648,7 @@ export async function streamLLMWithTools(
8520
8648
  name: ev.name,
8521
8649
  args: ev.args,
8522
8650
  ...(ev.providerMeta !== undefined ? { providerMeta: ev.providerMeta } : {}),
8651
+ ...(ev.argsInvalid !== undefined ? { argsInvalid: ev.argsInvalid } : {}),
8523
8652
  });
8524
8653
  } else if (ev.type === 'reasoning') {
8525
8654
  // Forward to the optional reasoning handler. Codex Responses
@@ -8660,11 +8789,12 @@ export async function streamLLMWithTools(
8660
8789
  if (pendingCalls.length === 0 && turnText.length === 0) {
8661
8790
  if (emptyRetries >= MAX_EMPTY_RETRIES) {
8662
8791
  const notice = buildNoFinalSynthesisNotice('empty-turn');
8663
- const finalText = finalizeVisibleAssistantText(
8792
+ const visibleText = finalizeVisibleAssistantText(
8664
8793
  appendFinalSynthesisNotice(fullText, notice),
8665
8794
  notice,
8666
8795
  sawToolRound,
8667
8796
  );
8797
+ const finalText = `${buildNoFinalSynthesisLead('empty-turn', toolCallHistory.length)}\n\n${visibleText}`;
8668
8798
  handlers.onText('', finalText);
8669
8799
  debug.log('llm.router', 'tool-loop.empty-turn.give-up', {
8670
8800
  turn, emptyRetries, finalTextInjected: true,
@@ -9558,6 +9688,22 @@ export async function streamLLMWithTools(
9558
9688
  return { result: stub, isError: true, phaseRejected: false };
9559
9689
  }
9560
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
+ }
9561
9707
  // Codex-family same-args dedup guard (fix L-2). Scope is
9562
9708
  // EXPLORATORY_TOOLS only — repeating Bash/RunShell/Edit/Write
9563
9709
  // is often legitimate (retry after a fix, apply-then-verify,
@@ -10639,11 +10785,14 @@ export async function streamLLMWithTools(
10639
10785
  });
10640
10786
  }
10641
10787
  const emittedText = synthesizedText ?? noticeWithFallback;
10642
- const finalText = finalizeVisibleAssistantText(
10788
+ const visibleText = finalizeVisibleAssistantText(
10643
10789
  appendFinalSynthesisNotice(fullText, emittedText),
10644
10790
  emittedText,
10645
10791
  loopTermination === 'aborted' ? false : sawToolRound,
10646
10792
  );
10793
+ const finalText = loopTermination === 'budget-exhausted' && synthesizedText === null
10794
+ ? `${buildNoFinalSynthesisLead(loopTermination, toolCallHistory.length)}\n\n${visibleText}`
10795
+ : visibleText;
10647
10796
  // Skip post-emit when synthesis was already streamed live AND
10648
10797
  // finalText matches synthesizedText. Emit when synthesis failed
10649
10798
  // (fallback notice) OR finalization enriched the text.
@@ -10788,13 +10937,21 @@ function makeOpenAICompatProvider(
10788
10937
  if (!apiKey && !grokSub) {
10789
10938
  throw new Error(`${name} unavailable: configure apiKey via \`elanous setup\``);
10790
10939
  }
10791
- 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
+ }
10792
10950
  // Image-pipeline P3.5 — gate the synthetic follow-up workaround
10793
10951
  // on the userMessage axis for the active model + brand. `name`
10794
10952
  // is 'grok' or 'openai' for makeOpenAICompatProvider callers.
10795
10953
  // P-3 §6.9 (2026-05-07) — same lookup also gates user-message
10796
10954
  // image blocks in the wire.
10797
- const activeModel = opts.model || model;
10798
10955
  const brand = name as Parameters<typeof isVisionCapableModel>[0];
10799
10956
  const followup = isVisionCapableModel(brand, activeModel, 'userMessage');
10800
10957
  // 구독이 있으면 «엔드포인트와 자격이 통째로» 바뀐다(cli-chat-proxy + Bearer).
@@ -10806,16 +10963,41 @@ function makeOpenAICompatProvider(
10806
10963
  if (useSub) {
10807
10964
  debug.log('llm.grok', 'credential', { kind: useSub.kind, source: useSub.source, baseUrl: useSub.baseUrl, via: 'compat-provider' });
10808
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
+ }
10809
10995
  yield* streamOpenAIEvents(
10810
10996
  useSub ? `${useSub.baseUrl}/chat/completions` : resolvedUrl,
10811
10997
  useSub ? useSub.token : apiKey,
10812
10998
  {
10813
10999
  model: wire.model ? wire.model(activeModel) : activeModel,
10814
- messages: messages.flatMap((m) => toOpenAIMessages(m, {
10815
- acceptToolImagesViaFollowup: followup,
10816
- acceptUserMessageImages: followup,
10817
- ...(name === 'openrouter' ? { echoReasoningDetails: true } : {}),
10818
- })),
11000
+ messages: wireMessages,
10819
11001
  ...(() => {
10820
11002
  const fields = openAiCompatSamplingFields(brand, activeModel, opts.temperature ?? 0.3, opts.maxTokens ?? 2048);
10821
11003
  // ⛔ 2026-09-23 — OpenRouter 뒤의 추론 모델(kimi·glm·qwen …)은 기본 0.3 을 강제하면 안 된다:
@@ -10829,10 +11011,16 @@ function makeOpenAICompatProvider(
10829
11011
  return fields;
10830
11012
  })(),
10831
11013
  ...(tools ? { tools } : {}),
11014
+ ...(toolChoice !== undefined ? { tool_choice: toolChoice } : {}),
10832
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 } : {}),
10833
11021
  },
10834
11022
  opts.signal,
10835
- useSub ? useSub.headers : wire.headers,
11023
+ useSub ? useSub.headers : (sticky ? { ...wire.headers, 'x-session-id': sticky.key } : wire.headers),
10836
11024
  );
10837
11025
  },
10838
11026
  async *chat(messages, opts = {}) { yield* textOnly(this.streamChat!(messages, opts)); },
@@ -10852,7 +11040,18 @@ function makeOpenRouterProvider(cfg: UCLLMConfig): LLMProvider {
10852
11040
  OPENROUTER_API_URL,
10853
11041
  { ...cfg, apiKey: cfg.apiKey || getOpenRouterApiKey() },
10854
11042
  // ⭐ BACKLOG C7 — `usage:{include:true}` 면 마지막 청크 `usage.cost` 에 «실제 청구액»이 온다(추정 아님).
10855
- { 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
+ },
10856
11055
  );
10857
11056
  // ⛔ 2026-09-23 — OpenRouter 의 `max_tokens` 는 «추론 토큰까지» 센다. 호환 경로 기본값 2048 이면 추론 모델이
10858
11057
  // 본문·도구 호출에 닿기 전에 잘렸다(실측 glm-5.3: 2048 → finish=length). 오전 판은 바닥 16384 를 뒀고,
@@ -10861,11 +11060,77 @@ function makeOpenRouterProvider(cfg: UCLLMConfig): LLMProvider {
10861
11060
  return inner;
10862
11061
  }
10863
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
+
10864
11103
  /** `openrouter/moonshotai/kimi-k3` → `moonshotai/kimi-k3`. 접두가 없으면 그대로. */
10865
11104
  export function openRouterWireModel(model: string): string {
10866
11105
  return model.startsWith('openrouter/') ? model.slice('openrouter/'.length) : model;
10867
11106
  }
10868
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
+
10869
11134
  /** Codex-specific provider. Prefers OAuth tokens from ~/.config/elanous/auth.json
10870
11135
  * (refreshing them when within the 120s buffer) and falls back to the
10871
11136
  * plain apiKey flow only when no tokens are on file. OAuth mode targets
@@ -11210,6 +11475,7 @@ export function inferProviderFromModel(model: string | undefined): string | null
11210
11475
  * its own configured default. */
11211
11476
  export function isModelCompatible(providerName: string, model: string | undefined): boolean {
11212
11477
  if (!model) return true;
11478
+ if (providerName === 'bedrock') return isBedrockCompatibleModel(model, inferProviderFromModel);
11213
11479
  const implied = inferProviderFromModel(model);
11214
11480
  if (implied === null) return true; // unknown prefix — let provider handle
11215
11481
  // openai-codex and openai accept each other's model families (gpt-*, codex-*).
@@ -11249,7 +11515,7 @@ export function anyProviderAvailable(userConfig?: UserConfig): boolean {
11249
11515
  } catch { return false; }
11250
11516
  }
11251
11517
  } catch { /* fall through to env check */ }
11252
- return Object.values(PROVIDERS).some(p => p.available());
11518
+ return Object.values(PROVIDERS).some(p => p.name !== 'bedrock' && p.available()); // bedrock 은 auto 후보가 아니다
11253
11519
  }
11254
11520
 
11255
11521
  /** 직결 배선이 없는 계열 → OpenRouter 에서 그 벤더의 대표 모델(사다리 `openrouter` 에 선 것). */
@@ -11291,6 +11557,10 @@ export function getProviderForConfig(
11291
11557
  if (!isKnownProviderName(resolvedProviderName)) {
11292
11558
  throw new Error(`unknown provider: ${resolvedProviderName}`);
11293
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
+ }
11294
11564
  return PROVIDERS[resolvedProviderName]!;
11295
11565
  }
11296
11566
  if (!isKnownProviderName(resolvedProviderName)) {
@@ -11330,9 +11600,10 @@ export function getProviderForConfig(
11330
11600
  case 'openai-codex':
11331
11601
  return makeCodexProvider(llm);
11332
11602
  case 'openrouter':
11333
- 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 });
11334
11604
  case 'anthropic':
11335
11605
  return makeAnthropicProvider(llm);
11606
+ case 'bedrock': return makeBedrockProvider(llm);
11336
11607
  case 'gemini':
11337
11608
  // Wave 1 (2026-05-04) — native @google/genai SDK. Previously
11338
11609
  // makeOpenAICompatProvider tunnel which couldn't carry