elanous 0.2.22 → 0.2.24

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