@fudrouter/fsrouter 0.6.72 → 0.6.74

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 (314) hide show
  1. package/dist/lib/headroom/detect.js +97 -7
  2. package/dist/lib/headroom/process.js +136 -4
  3. package/dist/open-sse/config/appConstants.js +23 -79
  4. package/dist/open-sse/config/cliFingerprints.js +1 -1
  5. package/dist/open-sse/config/errorConfig.js +0 -11
  6. package/dist/open-sse/config/grokCli.js +10 -0
  7. package/dist/open-sse/config/kiroConstants.js +99 -46
  8. package/dist/open-sse/config/runtimeConfig.js +2 -0
  9. package/dist/open-sse/config/ttsModels.js +2 -0
  10. package/dist/open-sse/executors/antigravity.js +250 -164
  11. package/dist/open-sse/executors/base.js +16 -11
  12. package/dist/open-sse/executors/codex.js +269 -1108
  13. package/dist/open-sse/executors/commandCode.js +1 -1
  14. package/dist/open-sse/executors/commandcode.js +10 -4
  15. package/dist/open-sse/executors/cursor.js +96 -203
  16. package/dist/open-sse/executors/default.js +146 -244
  17. package/dist/open-sse/executors/github.js +128 -73
  18. package/dist/open-sse/executors/grok-cli.js +527 -94
  19. package/dist/open-sse/executors/grok-web.js +5 -7
  20. package/dist/open-sse/executors/index.js +12 -0
  21. package/dist/open-sse/executors/kiro.js +150 -61
  22. package/dist/open-sse/executors/opencode-go.js +12 -4
  23. package/dist/open-sse/executors/opencode.js +1 -1
  24. package/dist/open-sse/executors/perplexity-web.js +20 -96
  25. package/dist/open-sse/executors/qoder.js +28 -18
  26. package/dist/open-sse/executors/vertex.js +53 -7
  27. package/dist/open-sse/executors/xiaomi-tokenplan.js +6 -5
  28. package/dist/open-sse/handlers/chatCore/nonStreamingHandler.js +97 -85
  29. package/dist/open-sse/handlers/chatCore/requestDetail.js +32 -8
  30. package/dist/open-sse/handlers/chatCore/sseToJsonHandler.js +13 -7
  31. package/dist/open-sse/handlers/chatCore/streamingHandler.js +74 -25
  32. package/dist/open-sse/handlers/chatCore.js +35 -41
  33. package/dist/open-sse/handlers/embeddingProviders/index.js +1 -0
  34. package/dist/open-sse/handlers/embeddingProviders/openai.js +8 -16
  35. package/dist/open-sse/handlers/imageProviders/blackForestLabs.js +2 -21
  36. package/dist/open-sse/handlers/imageProviders/cloudflareAi.js +2 -30
  37. package/dist/open-sse/handlers/imageProviders/codex.js +2 -20
  38. package/dist/open-sse/handlers/imageProviders/comfyui.js +5 -18
  39. package/dist/open-sse/handlers/imageProviders/falAi.js +2 -22
  40. package/dist/open-sse/handlers/imageProviders/gemini.js +2 -16
  41. package/dist/open-sse/handlers/imageProviders/huggingface.js +2 -17
  42. package/dist/open-sse/handlers/imageProviders/index.js +3 -4
  43. package/dist/open-sse/handlers/imageProviders/leonardo.js +1 -1
  44. package/dist/open-sse/handlers/imageProviders/nanobanana.js +4 -23
  45. package/dist/open-sse/handlers/imageProviders/openai.js +15 -43
  46. package/dist/open-sse/handlers/imageProviders/runwayml.js +2 -26
  47. package/dist/open-sse/handlers/imageProviders/sdwebui.js +4 -20
  48. package/dist/open-sse/handlers/imageProviders/stabilityAi.js +2 -26
  49. package/dist/open-sse/handlers/imageProviders/weavy.js +1 -1
  50. package/dist/open-sse/handlers/search/chatSearch.js +60 -14
  51. package/dist/open-sse/handlers/ttsProviders/gemini.js +14 -3
  52. package/dist/open-sse/handlers/ttsProviders/index.js +4 -2
  53. package/dist/open-sse/handlers/ttsProviders/openai.js +4 -1
  54. package/dist/open-sse/handlers/ttsProviders/openrouter.js +7 -4
  55. package/dist/open-sse/handlers/videoCore.js +166 -0
  56. package/dist/open-sse/handlers/videoProviders/weavy.js +1 -1
  57. package/dist/open-sse/mcp-server/catalog.js +1 -1
  58. package/dist/open-sse/mcp-server/server.js +2 -2
  59. package/dist/open-sse/mcp-server/tools/advancedTools.js +2 -2
  60. package/dist/open-sse/mcp-server/tools/agentSkillTools.js +1 -1
  61. package/dist/open-sse/mcp-server/tools/compressionTools.js +4 -4
  62. package/dist/open-sse/mcp-server/tools/gamificationTools.js +10 -10
  63. package/dist/open-sse/mcp-server/tools/githubSkillTools.js +1 -1
  64. package/dist/open-sse/mcp-server/tools/memoryTools.js +3 -3
  65. package/dist/open-sse/mcp-server/tools/notionTools.js +2 -2
  66. package/dist/open-sse/mcp-server/tools/obsidianTools.js +2 -2
  67. package/dist/open-sse/mcp-server/tools/pickFastestModel.js +1 -1
  68. package/dist/open-sse/mcp-server/tools/pluginTools.js +4 -4
  69. package/dist/open-sse/mcp-server/tools/skillTools.js +2 -2
  70. package/dist/open-sse/providers/capabilities.js +24 -4
  71. package/dist/open-sse/providers/registry/alicode-intl.js +1 -1
  72. package/dist/open-sse/providers/registry/anthropic.js +1 -8
  73. package/dist/open-sse/providers/registry/codex.js +0 -9
  74. package/dist/open-sse/providers/registry/cohere.js +0 -2
  75. package/dist/open-sse/providers/registry/gemini.js +0 -2
  76. package/dist/open-sse/providers/registry/github.js +9 -6
  77. package/dist/open-sse/providers/registry/grok-cli.js +28 -18
  78. package/dist/open-sse/providers/registry/index.js +74 -80
  79. package/dist/open-sse/providers/registry/kiro.js +12 -0
  80. package/dist/open-sse/providers/registry/mistral.js +0 -3
  81. package/dist/open-sse/providers/registry/openai.js +0 -3
  82. package/dist/open-sse/providers/registry/perplexity.js +0 -2
  83. package/dist/open-sse/providers/registry/xai.js +5 -3
  84. package/dist/open-sse/rtk/autodetect.js +10 -2
  85. package/dist/open-sse/rtk/caveman.js +2 -93
  86. package/dist/open-sse/rtk/cavemanPrompts.js +34 -2
  87. package/dist/open-sse/rtk/constants.js +7 -2
  88. package/dist/open-sse/rtk/headroom.js +133 -0
  89. package/dist/open-sse/rtk/ponytail.js +1 -1
  90. package/dist/open-sse/rtk/registry.js +2 -0
  91. package/dist/open-sse/services/accountFallback.js +0 -108
  92. package/dist/open-sse/services/combo/quotaExhaustionCutoff.js +2 -2
  93. package/dist/open-sse/services/combo/quotaShareStrategy.js +1 -1
  94. package/dist/open-sse/services/combo/resolveAutoStrategy.js +1 -1
  95. package/dist/open-sse/services/combo/sessionStickiness.js +1 -1
  96. package/dist/open-sse/services/combo/targetSorters.js +2 -2
  97. package/dist/open-sse/services/combo/validateQuality.js +1 -1
  98. package/dist/open-sse/services/comboConfig.js +1 -1
  99. package/dist/open-sse/services/emergencyFallback.js +1 -1
  100. package/dist/open-sse/services/grokCliModels.js +127 -0
  101. package/dist/open-sse/services/model.js +7 -1
  102. package/dist/open-sse/services/provider.js +1 -1
  103. package/dist/open-sse/services/proxyAutoSelector.js +1 -1
  104. package/dist/open-sse/services/tokenRefresh/providers.js +3 -3
  105. package/dist/open-sse/services/usage/codex.js +148 -214
  106. package/dist/open-sse/services/usage/grok-cli.js +61 -7
  107. package/dist/open-sse/services/usage/misc.js +0 -19
  108. package/dist/open-sse/services/usage.js +0 -2
  109. package/dist/open-sse/translator/concerns/paramSupport.js +2 -2
  110. package/dist/open-sse/translator/concerns/thinkingUnified.js +6 -0
  111. package/dist/open-sse/translator/index.js +97 -59
  112. package/dist/open-sse/translator/request/claude-to-kiro.js +67 -40
  113. package/dist/open-sse/translator/request/openai-responses.js +1 -0
  114. package/dist/open-sse/translator/request/openai-to-commandcode.js +0 -4
  115. package/dist/open-sse/translator/request/openai-to-kiro.js +49 -20
  116. package/dist/open-sse/translator/response/commandcode-to-openai.js +0 -4
  117. package/dist/open-sse/utils/bypassHandler.js +18 -3
  118. package/dist/open-sse/utils/claudeCloaking.js +15 -5
  119. package/dist/open-sse/utils/cursorImages.js +1 -1
  120. package/dist/open-sse/utils/error.js +0 -17
  121. package/dist/open-sse/utils/keepaliveThreshold.js +4 -4
  122. package/dist/open-sse/utils/kiroSessionReplay.js +125 -0
  123. package/dist/open-sse/utils/noThinkingAlias.js +1 -1
  124. package/dist/open-sse/utils/proxyFetch.js +0 -1
  125. package/dist/open-sse/utils/reasoningContentInjector.js +4 -7
  126. package/dist/open-sse/utils/responsesStatePolicy.js +1 -1
  127. package/dist/open-sse/utils/responsesStreamHelpers.js +1 -0
  128. package/dist/open-sse/utils/sessionManager.js +49 -22
  129. package/dist/open-sse/utils/stream.js +54 -77
  130. package/dist/open-sse/utils/streamHandler.js +19 -15
  131. package/dist/open-sse/utils/streamHelpers.js +2 -17
  132. package/dist/open-sse/utils/usageTracking.js +103 -12
  133. package/dist/routes/headroom/extras/route.js +58 -0
  134. package/dist/routes/headroom/restart/route.js +33 -0
  135. package/open-sse/config/appConstants.js +23 -79
  136. package/open-sse/config/errorConfig.js +0 -11
  137. package/open-sse/config/grokCli.js +10 -0
  138. package/open-sse/config/kiroConstants.js +99 -46
  139. package/open-sse/config/runtimeConfig.js +2 -0
  140. package/open-sse/config/ttsModels.js +2 -0
  141. package/open-sse/executors/antigravity.js +250 -164
  142. package/open-sse/executors/base.js +16 -11
  143. package/open-sse/executors/codex.js +269 -1108
  144. package/open-sse/executors/commandcode.js +10 -4
  145. package/open-sse/executors/cursor.js +96 -203
  146. package/open-sse/executors/default.js +146 -244
  147. package/open-sse/executors/github.js +128 -73
  148. package/open-sse/executors/grok-cli.js +527 -94
  149. package/open-sse/executors/grok-web.js +5 -7
  150. package/open-sse/executors/index.js +12 -0
  151. package/open-sse/executors/kiro.js +150 -61
  152. package/open-sse/executors/opencode-go.js +12 -4
  153. package/open-sse/executors/opencode.js +1 -1
  154. package/open-sse/executors/perplexity-web.js +20 -96
  155. package/open-sse/executors/qoder.js +28 -18
  156. package/open-sse/executors/vertex.js +53 -7
  157. package/open-sse/executors/xiaomi-tokenplan.js +6 -5
  158. package/open-sse/handlers/chatCore/nonStreamingHandler.js +97 -85
  159. package/open-sse/handlers/chatCore/requestDetail.js +32 -8
  160. package/open-sse/handlers/chatCore/sseToJsonHandler.js +13 -7
  161. package/open-sse/handlers/chatCore/streamingHandler.js +74 -25
  162. package/open-sse/handlers/chatCore.js +35 -41
  163. package/open-sse/handlers/embeddingProviders/index.js +1 -0
  164. package/open-sse/handlers/embeddingProviders/openai.js +8 -16
  165. package/open-sse/handlers/imageProviders/blackForestLabs.js +2 -21
  166. package/open-sse/handlers/imageProviders/cloudflareAi.js +2 -30
  167. package/open-sse/handlers/imageProviders/codex.js +2 -20
  168. package/open-sse/handlers/imageProviders/comfyui.js +5 -18
  169. package/open-sse/handlers/imageProviders/falAi.js +2 -22
  170. package/open-sse/handlers/imageProviders/gemini.js +2 -16
  171. package/open-sse/handlers/imageProviders/huggingface.js +2 -17
  172. package/open-sse/handlers/imageProviders/index.js +3 -4
  173. package/open-sse/handlers/imageProviders/leonardo.js +1 -1
  174. package/open-sse/handlers/imageProviders/nanobanana.js +4 -23
  175. package/open-sse/handlers/imageProviders/openai.js +15 -43
  176. package/open-sse/handlers/imageProviders/runwayml.js +2 -26
  177. package/open-sse/handlers/imageProviders/sdwebui.js +4 -20
  178. package/open-sse/handlers/imageProviders/stabilityAi.js +2 -26
  179. package/open-sse/handlers/imageProviders/weavy.js +1 -1
  180. package/open-sse/handlers/search/chatSearch.js +60 -14
  181. package/open-sse/handlers/ttsProviders/gemini.js +14 -3
  182. package/open-sse/handlers/ttsProviders/index.js +4 -2
  183. package/open-sse/handlers/ttsProviders/openai.js +4 -1
  184. package/open-sse/handlers/ttsProviders/openrouter.js +7 -4
  185. package/open-sse/handlers/videoCore.js +166 -0
  186. package/open-sse/handlers/videoProviders/weavy.js +1 -1
  187. package/open-sse/mcp-server/audit.js +1 -1
  188. package/open-sse/mcp-server/catalog.js +2 -2
  189. package/open-sse/mcp-server/descriptionCompressor.js +1 -1
  190. package/open-sse/mcp-server/mcpCallerIdentity.js +1 -1
  191. package/open-sse/mcp-server/schemas/tools.js +1 -1
  192. package/open-sse/mcp-server/server.js +4 -4
  193. package/open-sse/mcp-server/tools/advancedTools.js +5 -5
  194. package/open-sse/mcp-server/tools/agentSkillTools.js +1 -1
  195. package/open-sse/mcp-server/tools/compressionTools.js +4 -4
  196. package/open-sse/mcp-server/tools/gamificationTools.js +10 -10
  197. package/open-sse/mcp-server/tools/githubSkillTools.js +1 -1
  198. package/open-sse/mcp-server/tools/memoryTools.js +3 -3
  199. package/open-sse/mcp-server/tools/notionTools.js +2 -2
  200. package/open-sse/mcp-server/tools/obsidianTools.js +2 -2
  201. package/open-sse/mcp-server/tools/pickFastestModel.js +3 -3
  202. package/open-sse/mcp-server/tools/pluginTools.js +4 -4
  203. package/open-sse/mcp-server/tools/skillTools.js +2 -2
  204. package/open-sse/providers/capabilities.js +24 -4
  205. package/open-sse/providers/registry/alicode-intl.js +1 -1
  206. package/open-sse/providers/registry/anthropic.js +1 -8
  207. package/open-sse/providers/registry/codex.js +0 -9
  208. package/open-sse/providers/registry/cohere.js +0 -2
  209. package/open-sse/providers/registry/gemini.js +0 -2
  210. package/open-sse/providers/registry/github.js +9 -6
  211. package/open-sse/providers/registry/grok-cli.js +28 -18
  212. package/open-sse/providers/registry/index.js +74 -80
  213. package/open-sse/providers/registry/kiro.js +12 -0
  214. package/open-sse/providers/registry/mistral.js +0 -3
  215. package/open-sse/providers/registry/openai.js +0 -3
  216. package/open-sse/providers/registry/perplexity.js +0 -2
  217. package/open-sse/providers/registry/xai.js +5 -3
  218. package/open-sse/rtk/autodetect.js +10 -2
  219. package/open-sse/rtk/caveman.js +2 -93
  220. package/open-sse/rtk/cavemanPrompts.js +34 -2
  221. package/open-sse/rtk/constants.js +7 -2
  222. package/open-sse/rtk/headroom.js +133 -0
  223. package/open-sse/rtk/ponytail.js +1 -1
  224. package/open-sse/rtk/registry.js +2 -0
  225. package/open-sse/services/accountFallback.js +0 -108
  226. package/open-sse/services/combo/quotaExhaustionCutoff.js +2 -2
  227. package/open-sse/services/combo/quotaShareStrategy.js +1 -1
  228. package/open-sse/services/combo/resolveAutoStrategy.js +1 -1
  229. package/open-sse/services/combo/sessionStickiness.js +1 -1
  230. package/open-sse/services/combo/shadowRouting.js +1 -1
  231. package/open-sse/services/combo/targetSorters.js +4 -4
  232. package/open-sse/services/combo/validateQuality.js +1 -1
  233. package/open-sse/services/evalRouting.js +1 -1
  234. package/open-sse/services/grokCliModels.js +127 -0
  235. package/open-sse/services/model.js +7 -1
  236. package/open-sse/services/modelCapabilities.js +1 -1
  237. package/open-sse/services/modelFamilyFallback.js +1 -1
  238. package/open-sse/services/provider.js +1 -1
  239. package/open-sse/services/providerCooldownTracker.js +1 -1
  240. package/open-sse/services/rateLimitManager.js +1 -1
  241. package/open-sse/services/tokenRefresh/providers.js +3 -3
  242. package/open-sse/services/usage/codex.js +148 -214
  243. package/open-sse/services/usage/grok-cli.js +61 -7
  244. package/open-sse/services/usage/misc.js +0 -19
  245. package/open-sse/services/usage.js +0 -2
  246. package/open-sse/translator/concerns/paramSupport.js +2 -2
  247. package/open-sse/translator/concerns/thinkingUnified.js +6 -0
  248. package/open-sse/translator/index.js +97 -59
  249. package/open-sse/translator/request/claude-to-kiro.js +67 -40
  250. package/open-sse/translator/request/openai-responses.js +1 -0
  251. package/open-sse/translator/request/openai-to-commandcode.js +0 -4
  252. package/open-sse/translator/request/openai-to-kiro.js +49 -20
  253. package/open-sse/translator/response/commandcode-to-openai.js +0 -4
  254. package/open-sse/utils/bypassHandler.js +18 -3
  255. package/open-sse/utils/claudeCloaking.js +15 -5
  256. package/open-sse/utils/error.js +0 -17
  257. package/open-sse/utils/kiroSessionReplay.js +125 -0
  258. package/open-sse/utils/logger.js +1 -1
  259. package/open-sse/utils/proxyFetch.js +0 -1
  260. package/open-sse/utils/reasoningContentInjector.js +4 -7
  261. package/open-sse/utils/responsesStreamHelpers.js +1 -0
  262. package/open-sse/utils/sessionManager.js +49 -22
  263. package/open-sse/utils/stream.js +54 -77
  264. package/open-sse/utils/streamHandler.js +19 -15
  265. package/open-sse/utils/streamHelpers.js +2 -17
  266. package/open-sse/utils/usageTracking.js +103 -12
  267. package/package.json +4 -7
  268. package/public/assets/EndpointPageClient.C2WMTYy0.js +6 -0
  269. package/public/assets/{Loading.Bj-WGl4k.js → Loading.BHPtQ9vj.js} +1 -1
  270. package/public/assets/{NoAuthProxyCard.qAv57b-0.js → NoAuthProxyCard.BDcXaWvM.js} +1 -1
  271. package/public/assets/index.Be3gbrBl.js +89 -0
  272. package/public/assets/index.COMgQZYj.css +1 -0
  273. package/public/assets/{page.CbkENBd5.js → page.-lpNgYAw.js} +1 -1
  274. package/public/assets/{page.CssmrzTT.js → page.11hpNKmq.js} +1 -1
  275. package/public/assets/{page.C72FTTJr.js → page.B-LxsnqU.js} +1 -1
  276. package/public/assets/{page.sOFOrxqq.js → page.B-dzeIUC.js} +1 -1
  277. package/public/assets/{page.CsxWmPoI.js → page.B-nBR75u.js} +1 -1
  278. package/public/assets/{page.Dx_GRRdT.js → page.B3QqvLep.js} +1 -1
  279. package/public/assets/{page.DPyOkPVo.js → page.B8xdkCWA.js} +1 -1
  280. package/public/assets/{page.DUI8kqOY.js → page.BFb7yUd8.js} +1 -1
  281. package/public/assets/page.BbPPdoas.js +1 -0
  282. package/public/assets/page.BdS20a1O.js +1 -0
  283. package/public/assets/{page.DibhF7f-.js → page.BfmI9KYe.js} +1 -1
  284. package/public/assets/{page.DX4Nno6M.js → page.BgGJovOg.js} +1 -1
  285. package/public/assets/{page.BnmTC5jG.js → page.C0gBvR4O.js} +1 -1
  286. package/public/assets/{page.D5gj98Oe.js → page.C6bYizL7.js} +1 -1
  287. package/public/assets/{page.vla5Mzki.js → page.C8sLEMa6.js} +1 -1
  288. package/public/assets/{page.CXd_R9yU.js → page.CCNsZBXp.js} +1 -1
  289. package/public/assets/{page.CQlVGoXg.js → page.CF_YSLwP.js} +1 -1
  290. package/public/assets/{page.BbO1pspY.js → page.CPTtRDxw.js} +1 -1
  291. package/public/assets/{page.D1oKew1j.js → page.CdMmlUEm.js} +1 -1
  292. package/public/assets/{page.DxMDTbSx.js → page.Cged1bOZ.js} +1 -1
  293. package/public/assets/{page.Cj5h09Zo.js → page.Ch647dVk.js} +1 -1
  294. package/public/assets/{page.DVIHRbxB.js → page.CpvXDkQF.js} +1 -1
  295. package/public/assets/{page.i4KDuWcM.js → page.CrBl7f8N.js} +1 -1
  296. package/public/assets/{page.BSLJ4tx5.js → page.CrP7niA2.js} +1 -1
  297. package/public/assets/{page.CnTop8Zt.js → page.CvUFZzXr.js} +1 -1
  298. package/public/assets/{page.O2ddJYoT.js → page.CyUqJPmx.js} +1 -1
  299. package/public/assets/{page.DBhu4Arl.js → page.D8Rp8fFR.js} +1 -1
  300. package/public/assets/{page.CPZav1_c.js → page.Df9qtrdG.js} +1 -1
  301. package/public/assets/{page.Qkkv8roc.js → page.DiL4Gwqe.js} +1 -1
  302. package/public/assets/{page.BdmJ3yY3.js → page.Dl1apZE2.js} +1 -1
  303. package/public/assets/{page.1qjqvrwX.js → page.HV0w1d5C.js} +1 -1
  304. package/public/assets/{page.ChX1NqmC.js → page.N1x4YL8_.js} +1 -1
  305. package/public/assets/{page.Dh5f0XJC.js → page.P2Ny5veR.js} +1 -1
  306. package/public/assets/{page.CSs3-gdt.js → page.fOOCr18J.js} +1 -1
  307. package/public/assets/{page.Ir7KvKcF.js → page.sUIPWIiF.js} +1 -1
  308. package/public/assets/{page.CzlQTyAL.js → page.tE7PpWYW.js} +1 -1
  309. package/public/assets/{page.DzZLqI5Q.js → page.uziaGZsT.js} +1 -1
  310. package/public/index.html +2 -2
  311. package/public/assets/EndpointPageClient.LyNNvZ4z.js +0 -6
  312. package/public/assets/index.BuPfZebu.css +0 -1
  313. package/public/assets/index.CShjRV_B.js +0 -89
  314. package/public/assets/page.DD_czjjP.js +0 -1
@@ -4,9 +4,13 @@ import { OAUTH_ENDPOINTS, GITHUB_COPILOT } from "../config/appConstants.js";
4
4
  import { HTTP_STATUS } from "../config/runtimeConfig.js";
5
5
  import { openaiToOpenAIResponsesRequest } from "../translator/request/openai-responses.js";
6
6
  import { openaiResponsesToOpenAIResponse } from "../translator/response/openai-responses.js";
7
- import { initState } from "../translator/index.js";
7
+ import { initState, translateRequest, translateResponse } from "../translator/index.js";
8
+ import { FORMATS } from "../translator/formats.js";
8
9
  import { parseSSELine, formatSSE } from "../utils/streamHelpers.js";
9
10
  import { proxyAwareFetch } from "../utils/proxyFetch.js";
11
+ import { stripUnsupportedParams } from "../translator/concerns/paramSupport.js";
12
+ import { SSE_DONE } from "../utils/sseConstants.js";
13
+ import { ANTHROPIC_API_VERSION } from "../providers/shared.js";
10
14
  import crypto from "crypto";
11
15
 
12
16
  export class GithubExecutor extends BaseExecutor {
@@ -15,6 +19,16 @@ export class GithubExecutor extends BaseExecutor {
15
19
  this.knownCodexModels = new Set();
16
20
  }
17
21
 
22
+ // Claude models get routed to Copilot's Anthropic-native /v1/messages shim (see
23
+ // executeWithMessagesEndpoint below) — the only Copilot endpoint that surfaces
24
+ // prompt-cache token counts. gpt/gemini/grok models stay on /chat/completions
25
+ // (or /responses). Name-pattern check, not a registry field: Copilot's live model
26
+ // catalog (services/copilotModels.js) regularly exposes claude-* variants ahead
27
+ // of the static registry (registry/github.js).
28
+ isClaudeModel(model) {
29
+ return /claude/i.test(model || "");
30
+ }
31
+
18
32
  buildUrl(model, stream, urlIndex = 0) {
19
33
  return this.config.baseUrl;
20
34
  }
@@ -33,47 +47,20 @@ export class GithubExecutor extends BaseExecutor {
33
47
  "x-request-id": crypto.randomUUID?.() || `${Date.now()}-${Math.random().toString(36).slice(2)}`,
34
48
  "x-vscode-user-agent-library-version": "electron-fetch",
35
49
  "X-Initiator": "user",
50
+ // Harmless no-op on /chat/completions and /responses; required by /v1/messages.
51
+ "anthropic-version": ANTHROPIC_API_VERSION,
36
52
  "Accept": stream ? "text/event-stream" : "application/json"
37
53
  };
38
54
  }
39
55
 
40
- // Sanitize messages for GitHub Copilot /chat/completions endpoint.
56
+ // Sanitize messages for GitHub Copilot /chat/completions endpoint (gpt/gemini/grok models —
57
+ // claude models never reach this, see execute() below).
41
58
  // The endpoint only accepts 'text' and 'image_url' content part types.
42
59
  // Tool-related content (tool_use, tool_result, thinking) must be serialized as text.
43
60
  sanitizeMessagesForChatCompletions(body) {
44
61
  if (!body?.messages) return body;
45
62
 
46
63
  const sanitized = { ...body };
47
-
48
- // Handle response_format for Claude models via GitHub
49
- // GitHub's internal translation doesn't respect response_format, so we inject it as a system prompt
50
- // AND prepend a reminder to the last user message for maximum effectiveness
51
- if (body.response_format && body.model?.includes('claude')) {
52
- const responseFormat = body.response_format;
53
- let systemInstruction = '';
54
- if (responseFormat.type === 'json_schema' && responseFormat.json_schema?.schema) {
55
- systemInstruction = 'CRITICAL: You must ONLY output raw JSON. Never use markdown code blocks. Never use backticks. Never wrap JSON in triple backticks. Output ONLY the raw JSON object.';
56
- } else if (responseFormat.type === 'json_object') {
57
- systemInstruction = 'CRITICAL: You must ONLY output raw JSON. Never use markdown code blocks. Never use backticks.';
58
- }
59
- if (systemInstruction) {
60
- // Add to system message
61
- const systemIdx = body.messages.findIndex(m => m.role === 'system');
62
- if (systemIdx >= 0) {
63
- body.messages[systemIdx].content = systemInstruction + '\n\n' + body.messages[systemIdx].content;
64
- } else {
65
- body.messages.unshift({ role: 'system', content: systemInstruction });
66
- }
67
-
68
- // Also prepend to the last user message as a reminder
69
- const lastUserIdx = body.messages.map((m, i) => m.role === 'user' ? i : -1).filter(i => i >= 0).pop();
70
- if (lastUserIdx >= 0) {
71
- const userMsg = body.messages[lastUserIdx];
72
- const userContent = typeof userMsg.content === 'string' ? userMsg.content : JSON.stringify(userMsg.content);
73
- userMsg.content = 'Respond with ONLY raw JSON (no markdown, no backticks, no code blocks): ' + userContent;
74
- }
75
- }
76
- }
77
64
  sanitized.messages = body.messages.map(msg => {
78
65
  // assistant messages with only tool_calls have content: null — leave as-is
79
66
  if (!msg.content) return msg;
@@ -108,54 +95,18 @@ export class GithubExecutor extends BaseExecutor {
108
95
  return /gpt-5|o[134]-/i.test(model);
109
96
  }
110
97
 
111
- // Some models (like gpt-5.4) don't support the temperature parameter
112
- supportsTemperature(model) {
113
- // gpt-5.4 and similar newer models don't support temperature
114
- return !/gpt-5\.4/i.test(model);
115
- }
116
-
117
- // GitHub Copilot /chat/completions rejects Claude-style thinking payloads
118
- // (OpenClaw sends thinking: { type: "enabled" } → upstream 400).
119
- // GPT-5 family on Copilot DOES honor reasoning_effort, so only strip for Claude. (#713)
120
- supportsThinking(model) {
121
- return !/claude/i.test(model);
122
- }
123
-
124
- // reasoning_effort works for GPT-5 family AND Claude Opus 4.6 / Sonnet 4.6
125
- // on GitHub Copilot. Only strip for models that don't support it:
126
- // Claude Haiku 4.5, Claude Opus 4.7 (rejected upstream).
127
- supportsReasoningEffort(model) {
128
- const m = model.toLowerCase();
129
- // Claude models that DO support reasoning_effort
130
- if (/claude.*opus.*4\.6/i.test(m) || /claude.*sonnet.*4\.6/i.test(m)) return true;
131
- // All other Claude models: strip
132
- if (/claude/i.test(model)) return false;
133
- // GPT-5 family, Gemini, etc.: keep
134
- return true;
135
- }
136
-
137
98
  transformRequest(model, body, stream, credentials) {
138
99
  const transformed = { ...body };
139
100
  if (this.requiresMaxCompletionTokens(model) && transformed.max_tokens !== undefined) {
140
101
  transformed.max_completion_tokens = transformed.max_tokens;
141
102
  delete transformed.max_tokens;
142
103
  }
143
- // Strip temperature for models that don't support it
144
- if (!this.supportsTemperature(model) && transformed.temperature !== undefined) {
145
- delete transformed.temperature;
146
- }
147
- // Always strip Claude-style thinking payload (Copilot doesn't understand it)
148
- if (!this.supportsThinking(model)) {
149
- delete transformed.thinking;
150
- }
151
104
  // "none" means no thinking — strip it so models that don't support "none" don't 400
152
105
  if (transformed.reasoning_effort === "none") {
153
106
  delete transformed.reasoning_effort;
154
107
  }
155
- // Strip reasoning_effort only for models that reject it
156
- if (!this.supportsReasoningEffort(model) && transformed.reasoning_effort !== undefined) {
157
- delete transformed.reasoning_effort;
158
- }
108
+ // Config-driven strip of params unsupported by this provider/model
109
+ stripUnsupportedParams("github", model, transformed);
159
110
  return transformed;
160
111
  }
161
112
 
@@ -172,6 +123,15 @@ export class GithubExecutor extends BaseExecutor {
172
123
  async execute(options) {
173
124
  const { model, log } = options;
174
125
 
126
+ // Claude models: route to Copilot's Anthropic-native /v1/messages shim — the only
127
+ // Copilot endpoint that surfaces prompt-cache token counts for Claude. Detected by
128
+ // model NAME (not a registry field): Copilot's live model catalog regularly exposes
129
+ // claude-* variants the static registry hasn't caught up with yet (see registry/github.js).
130
+ if (this.isClaudeModel(model)) {
131
+ log?.debug("GITHUB", `Using /v1/messages route for ${model}`);
132
+ return this.executeWithMessagesEndpoint(options);
133
+ }
134
+
175
135
  // Only use /responses for models that are explicitly known to need it (e.g. gpt codex models)
176
136
  // and that the /responses endpoint actually serves (excludes Gemini/Claude, see #1062).
177
137
  if (this.knownCodexModels.has(model) && this.supportsResponsesEndpoint(model)) {
@@ -179,8 +139,8 @@ export class GithubExecutor extends BaseExecutor {
179
139
  return this.executeWithResponsesEndpoint(options);
180
140
  }
181
141
 
182
- // Sanitize messages before sending to /chat/completions
183
- // This handles Claude models on GitHub Copilot which reject non-text/image_url content types
142
+ // Sanitize messages before sending to /chat/completions (gpt/gemini/grok — the
143
+ // endpoint rejects non-text/image_url content parts).
184
144
  const sanitizedOptions = {
185
145
  ...options,
186
146
  body: this.sanitizeMessagesForChatCompletions(options.body)
@@ -244,7 +204,7 @@ export class GithubExecutor extends BaseExecutor {
244
204
  if (!parsed) continue;
245
205
 
246
206
  if (parsed.done && stream === true) {
247
- controller.enqueue(new TextEncoder().encode("data: [DONE]\n\n"));
207
+ controller.enqueue(new TextEncoder().encode(SSE_DONE));
248
208
  continue;
249
209
  }
250
210
 
@@ -285,6 +245,101 @@ export class GithubExecutor extends BaseExecutor {
285
245
  };
286
246
  }
287
247
 
248
+ // Claude models arrive here OpenAI-shape (chatCore.js targets "openai" for github —
249
+ // see the note in execute() above), so we translate to Anthropic-native ourselves.
250
+ // This is what makes prepareClaudeRequest() (translator/formats/claude.js) inject
251
+ // cache_control — /chat/completions never gets there, so it never sees cache tokens.
252
+ async executeWithMessagesEndpoint({ model, body, stream, credentials, signal, log, proxyOptions = null }) {
253
+ const url = this.config.messagesUrl;
254
+ const headers = this.buildHeaders(credentials, stream);
255
+
256
+ // Force stream:true upstream regardless of client preference, same as
257
+ // executeWithResponsesEndpoint below — chatCore.js's non-streaming handler already
258
+ // knows how to buffer an SSE response into a single JSON reply when the client
259
+ // asked for stream:false.
260
+ const transformedBody = translateRequest(FORMATS.OPENAI, FORMATS.CLAUDE, model, body, true, credentials, "github");
261
+ // _toolNameMap is internal bookkeeping (see openai-to-claude.js) — chatCore.js
262
+ // normally strips it before dispatch and threads it into the response state to
263
+ // restore original tool names; we must do the same here, or Anthropic's strict
264
+ // schema rejects the extra field with a 400.
265
+ const toolNameMap = transformedBody._toolNameMap;
266
+ delete transformedBody._toolNameMap;
267
+
268
+ log?.debug("GITHUB", "Sending translated request to /v1/messages");
269
+
270
+ const response = await proxyAwareFetch(url, {
271
+ method: "POST",
272
+ headers,
273
+ body: JSON.stringify(transformedBody),
274
+ signal
275
+ }, proxyOptions);
276
+
277
+ if (!response.ok) {
278
+ return { response, url, headers, transformedBody };
279
+ }
280
+
281
+ const state = initState(FORMATS.CLAUDE);
282
+ state.model = model;
283
+ if (toolNameMap) state.toolNameMap = toolNameMap;
284
+
285
+ const decoder = new TextDecoder();
286
+ let buffer = "";
287
+
288
+ const emitAll = (controller, chunks) => {
289
+ for (const c of chunks) {
290
+ controller.enqueue(new TextEncoder().encode(formatSSE(c, "openai")));
291
+ }
292
+ };
293
+
294
+ const transformStream = new TransformStream({
295
+ async transform(chunk, controller) {
296
+ buffer += decoder.decode(chunk, { stream: true });
297
+ const lines = buffer.split("\n");
298
+
299
+ buffer = lines.pop() || "";
300
+
301
+ for (const line of lines) {
302
+ const trimmed = line.trim();
303
+ if (!trimmed) continue;
304
+
305
+ const parsed = parseSSELine(trimmed);
306
+ if (!parsed) continue;
307
+
308
+ if (parsed.done && stream === true) {
309
+ controller.enqueue(new TextEncoder().encode(SSE_DONE));
310
+ continue;
311
+ }
312
+
313
+ emitAll(controller, translateResponse(FORMATS.CLAUDE, FORMATS.OPENAI, parsed, state));
314
+ }
315
+ },
316
+ flush(controller) {
317
+ if (buffer.trim()) {
318
+ const parsed = parseSSELine(buffer.trim());
319
+ if (parsed && !parsed.done) {
320
+ emitAll(controller, translateResponse(FORMATS.CLAUDE, FORMATS.OPENAI, parsed, state));
321
+ }
322
+ }
323
+ }
324
+ });
325
+
326
+ if (!response.body) {
327
+ return { response: new Response("", { status: response.status, headers: response.headers }), url, headers, transformedBody };
328
+ }
329
+ const convertedStream = response.body.pipeThrough(transformStream);
330
+
331
+ return {
332
+ response: new Response(convertedStream, {
333
+ status: response.status,
334
+ statusText: response.statusText,
335
+ headers: response.headers
336
+ }),
337
+ url,
338
+ headers,
339
+ transformedBody
340
+ };
341
+ }
342
+
288
343
  async refreshCopilotToken(githubAccessToken, log, proxyOptions = null) {
289
344
  try {
290
345
  const response = await proxyAwareFetch("https://api.github.com/copilot_internal/v2/token", {