@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
@@ -9,10 +9,11 @@ import { createRequestLogger } from "../utils/requestLogger.js";
9
9
  import { getModelTargetFormat, getModelStrip, getModelUpstreamId, getModelType, PROVIDER_ID_TO_ALIAS } from "../config/providerModels.js";
10
10
  import { PROVIDERS } from "../config/providers.js";
11
11
  import { createErrorResult, parseUpstreamError, formatProviderError } from "../utils/error.js";
12
- import { HTTP_STATUS } from "../config/runtimeConfig.js";
12
+ import { HTTP_STATUS, TOKEN_SAVER_HEADER } from "../config/runtimeConfig.js";
13
13
  import { handleBypassRequest } from "../utils/bypassHandler.js";
14
14
  import { trackPendingRequest, appendRequestLog, saveRequestDetail } from '../../../dist/lib/usageDb.js';
15
15
  import { getExecutor } from "../executors/index.js";
16
+ import { supportsGrokCliReasoningEffort } from "../config/grokCli.js";
16
17
  import { buildRequestDetail, extractRequestConfig } from "./chatCore/requestDetail.js";
17
18
  import { handleForcedSSEToJson } from "./chatCore/sseToJsonHandler.js";
18
19
  import { handleNonStreamingResponse } from "./chatCore/nonStreamingHandler.js";
@@ -21,8 +22,8 @@ import { detectClientTool, isNativePassthrough } from "../utils/clientDetector.j
21
22
  import { dedupeTools } from "../utils/toolDeduper.js";
22
23
  import { injectCaveman } from "../rtk/caveman.js";
23
24
  import { injectPonytail } from "../rtk/ponytail.js";
24
- import { compressMessages } from "../rtk/index.js";
25
- import { compressWithHeadroom, formatHeadroomSizeLog, isHeadroomPhantomSavings } from "../rtk/headroom.js";
25
+ import { compressMessages, formatRtkLog } from "../rtk/index.js";
26
+ import { compressWithHeadroom, formatHeadroomLog, formatHeadroomSizeLog, isHeadroomPhantomSavings } from "../rtk/headroom.js";
26
27
  import { compressWithPxpipe } from "../rtk/pxpipe.js";
27
28
  import { getCapabilitiesForModel } from "../providers/capabilities.js";
28
29
  import { stripUnsupportedModalities } from "../translator/concerns/modality.js";
@@ -168,7 +169,8 @@ export async function handleChatCore({ body, modelInfo, credentials, log, onCred
168
169
  const msgN = translatedBody.messages?.length || translatedBody.input?.length || translatedBody.contents?.length || body.messages?.length || body.input?.length || 0;
169
170
  const toolN = translatedBody.tools?.length || body.tools?.length || 0;
170
171
  const fmtStr = passthrough ? `FMT: ${sourceFormat} (passthrough)` : `FMT: ${sourceFormat}→${targetFormat}`;
171
- const think = log.fmtThink?.(extractThinking(translatedBody));
172
+ const showThinking = provider !== "grok-cli" || supportsGrokCliReasoningEffort(model);
173
+ const think = showThinking ? log.fmtThink?.(extractThinking(translatedBody)) : null;
172
174
  const acc = credentials?.connectionName || credentials?.connectionId?.slice(0, 8) || "-";
173
175
  const parts = [
174
176
  `POST ${clientModel} → ${provider}/${model}`,
@@ -188,40 +190,37 @@ export async function handleChatCore({ body, modelInfo, credentials, log, onCred
188
190
  delete translatedBody.tools;
189
191
  }
190
192
 
191
- // Token-saver summary parts, printed as one "⚙" line at the end (only active ones)
192
- const xf = [];
193
+ // Per-request opt-out: client can bypass all token savers via header
194
+ const tokenSaverEnabled = clientRawRequest?.headers?.[TOKEN_SAVER_HEADER]?.toLowerCase() !== "off";
193
195
 
194
196
  // RTK: compress tool_result content
195
- const rtkStats = compressMessages(translatedBody, rtkEnabled);
196
- if (rtkStats?.hits?.length) {
197
- const saved = rtkStats.bytesBefore - rtkStats.bytesAfter;
198
- const pct = rtkStats.bytesBefore > 0 ? ((saved / rtkStats.bytesBefore) * 100).toFixed(0) : "0";
199
- xf.push(`RTK −${saved}B(${pct}%)`);
200
- }
197
+ const rtkStats = compressMessages(translatedBody, tokenSaverEnabled && rtkEnabled);
198
+ const rtkLine = formatRtkLog(rtkStats);
199
+ if (rtkLine) console.log(rtkLine);
201
200
 
202
201
  // Headroom: optional external proxy compression; fail open if proxy is absent.
203
202
  const headroomDiagnostics = {};
204
- const headroomStats = await compressWithHeadroom(translatedBody, { enabled: headroomEnabled, url: headroomUrl, model: upstreamModel, format: finalFormat, compressUserMessages: headroomCompressUserMessages, diagnostics: headroomDiagnostics });
205
- if (headroomStats) {
206
- const before = headroomStats.tokens_before || 0;
207
- const delta = headroomStats.tokens_saved || 0;
208
- const pct = before > 0 ? ((delta / before) * 100).toFixed(1) : "0";
209
- xf.push(`HEADROOM −${delta}tok(${pct}%)`);
203
+ const headroomStats = await compressWithHeadroom(translatedBody, { enabled: tokenSaverEnabled && headroomEnabled, url: headroomUrl, model: upstreamModel, format: finalFormat, compressUserMessages: headroomCompressUserMessages, diagnostics: headroomDiagnostics });
204
+ const headroomLine = formatHeadroomLog(headroomStats);
205
+ const headroomSizeLine = formatHeadroomSizeLog(headroomDiagnostics);
206
+ if (headroomLine) {
207
+ log?.info?.("HEADROOM", `${headroomLine}${headroomSizeLine ? ` | ${headroomSizeLine}` : ""}`);
210
208
  if (isHeadroomPhantomSavings(headroomStats, headroomDiagnostics)) {
211
209
  log?.warn?.("HEADROOM", `reported token delta, but outbound JSON shrank <5%; provider may bill near-original payload | ${formatHeadroomSizeLog(headroomDiagnostics)}`);
212
210
  }
213
- } else if (headroomEnabled) {
214
- log?.warn?.("HEADROOM", `skipped: ${headroomDiagnostics.reason || "compression unavailable"}${headroomDiagnostics.endpoint ? ` (${headroomDiagnostics.endpoint})` : ""}`);
215
- }
211
+ } else if (tokenSaverEnabled && headroomEnabled) log?.warn?.("HEADROOM", `skipped: ${headroomDiagnostics.reason || "compression unavailable"}${headroomDiagnostics.endpoint ? ` (${headroomDiagnostics.endpoint})` : ""}`);
212
+
213
+ // Token-saver flags accumulator for the single "⚙" log line below.
214
+ const xf = [];
216
215
 
217
216
  // Caveman: inject terse-style system prompt
218
- if (cavemanEnabled && cavemanLevel) {
217
+ if (tokenSaverEnabled && cavemanEnabled && cavemanLevel) {
219
218
  injectCaveman(translatedBody, finalFormat, cavemanLevel);
220
219
  xf.push(`CAVEMAN:${cavemanLevel}`);
221
220
  }
222
221
 
223
222
  // Ponytail: inject lazy-senior-dev system prompt
224
- if (ponytailEnabled && ponytailLevel) {
223
+ if (tokenSaverEnabled && ponytailEnabled && ponytailLevel) {
225
224
  injectPonytail(translatedBody, finalFormat, ponytailLevel);
226
225
  xf.push(`PONYTAIL:${ponytailLevel}`);
227
226
  }
@@ -243,20 +242,19 @@ export async function handleChatCore({ body, modelInfo, credentials, log, onCred
243
242
 
244
243
  const executor = getExecutor(provider);
245
244
  trackPendingRequest(model, provider, connectionId, true);
246
- try {
247
- appendRequestLog({ model, provider, connectionId, status: "PENDING" }).catch(() => { });
248
-
249
- const msgCount = translatedBody.messages?.length || translatedBody.input?.length || translatedBody.contents?.length || translatedBody.request?.contents?.length || 0;
250
- log?.debug?.("REQUEST", `${provider.toUpperCase()} | ${model} | ${msgCount} msgs`);
251
-
252
- const streamController = createStreamController({
253
- onDisconnect: (reason) => {
254
- trackPendingRequest(model, provider, connectionId, false);
255
- if (onDisconnect) onDisconnect(reason);
256
- },
257
- onError: () => trackPendingRequest(model, provider, connectionId, false),
258
- log, provider, model, reqTag
259
- });
245
+ appendRequestLog({ model, provider, connectionId, status: "PENDING" }).catch(() => { });
246
+
247
+ const msgCount = translatedBody.messages?.length || translatedBody.input?.length || translatedBody.contents?.length || translatedBody.request?.contents?.length || 0;
248
+ log?.debug?.("REQUEST", `${provider.toUpperCase()} | ${model} | ${msgCount} msgs`);
249
+
250
+ const streamController = createStreamController({
251
+ onDisconnect: (reason) => {
252
+ trackPendingRequest(model, provider, connectionId, false);
253
+ if (onDisconnect) onDisconnect(reason);
254
+ },
255
+ onError: () => trackPendingRequest(model, provider, connectionId, false),
256
+ log, provider, model, reqTag
257
+ });
260
258
 
261
259
  const proxyOptions = {
262
260
  connectionProxyEnabled: credentials?.providerSpecificData?.connectionProxyEnabled === true,
@@ -392,10 +390,6 @@ export async function handleChatCore({ body, modelInfo, credentials, log, onCred
392
390
  // Streaming response
393
391
  const { onStreamComplete, streamDetailId } = buildOnStreamComplete({ ...sharedCtx });
394
392
  return handleStreamingResponse({ ...sharedCtx, providerResponse, sourceFormat, targetFormat, userAgent, reqLogger, toolNameMap, streamController, onStreamComplete, streamDetailId });
395
- } catch (error) {
396
- trackPendingRequest(model, provider, connectionId, false);
397
- throw error;
398
- }
399
393
  }
400
394
 
401
395
  export function isTokenExpiringSoon(expiresAt, bufferMs = 5 * 60 * 1000) {
@@ -6,6 +6,7 @@ import openaiCompatNode from "./openaiCompatNode.js";
6
6
  const OPENAI_COMPAT_PROVIDERS = [
7
7
  "openai", "openrouter", "mistral", "voyage-ai", "fireworks",
8
8
  "together", "nebius", "github", "nvidia", "jina-ai",
9
+ "vercel-ai-gateway",
9
10
  ];
10
11
 
11
12
  const ADAPTERS = {
@@ -1,29 +1,21 @@
1
1
  // OpenAI-compatible embeddings adapter (most providers)
2
2
  import { bearerAuth } from "./_base.js";
3
+ import { PROVIDER_MEDIA } from "../../providers/index.js";
3
4
 
5
+ // media-only providers without a registry file keep URL here; rest derive from registry media.embeddingConfig.baseUrl
4
6
  const ENDPOINTS = {
5
- openai: "https://api.openai.com/v1/embeddings",
6
- openrouter: "https://openrouter.ai/api/v1/embeddings",
7
- mistral: "https://api.mistral.ai/v1/embeddings",
8
- "voyage-ai": "https://api.voyageai.com/v1/embeddings",
9
- fireworks: "https://api.fireworks.ai/inference/v1/embeddings",
10
- together: "https://api.together.xyz/v1/embeddings",
11
- nebius: "https://api.tokenfactory.nebius.com/v1/embeddings",
12
- github: "https://models.github.ai/inference/embeddings",
13
- nvidia: "https://integrate.api.nvidia.com/v1/embeddings",
14
7
  "jina-ai": "https://api.jina.ai/v1/embeddings",
15
8
  };
16
9
 
10
+ const embedCfg = (id) => PROVIDER_MEDIA[id]?.embeddingConfig || {};
11
+ const embedUrl = (id) => embedCfg(id).baseUrl || ENDPOINTS[id];
12
+
17
13
  export default function createOpenAIEmbeddingAdapter(providerId) {
14
+ const cfg = embedCfg(providerId);
18
15
  return {
19
- buildUrl: () => ENDPOINTS[providerId],
16
+ buildUrl: () => embedUrl(providerId),
20
17
  buildHeaders: (creds) => {
21
- const headers = { "Content-Type": "application/json", ...bearerAuth(creds) };
22
- if (providerId === "openrouter") {
23
- headers["HTTP-Referer"] = "https://endpoint-proxy.local";
24
- headers["X-Title"] = "Endpoint Proxy";
25
- }
26
- return headers;
18
+ return { "Content-Type": "application/json", ...bearerAuth(creds), ...(cfg.headers || {}) };
27
19
  },
28
20
  buildBody: (model, { input, encoding_format, dimensions }) => {
29
21
  const body = { model, input };
@@ -1,27 +1,8 @@
1
- /**
2
- * Black Forest Labs FLUX API adapter.
3
- *
4
- * Providers: black-forest-labs
5
- * Auth: x-key header (not Authorization Bearer) — uses apiKey or accessToken
6
- * Format: JSON body → async polling via task result URL
7
- * Polling: Yes — polls until status == "Ready"
8
- *
9
- * Supported request params:
10
- * @param {string} prompt - (required) Image description
11
- * @param {string} [model] - Model ID (e.g. "flux-pro-1.1", "flux-kontext-pro")
12
- * @param {string} [size] - Dimensions → parsed to width/height integers
13
- * @param {number} [seed] - Fixed seed
14
- * @param {number} [guidance] - Guidance scale
15
- * @param {number} [num_steps] - Diffusion steps
16
- * @param {string} [output_format="jpeg"] - "jpeg"|"png"|"webp"
17
- * @param {string} [image_url] - Reference image (Kontext edit models only)
18
- *
19
- * Response normalize: result.sample → { created, data: [{ url }] }.
20
- */
21
1
  // Black Forest Labs (FLUX) — async submit + polling_url
22
2
  import { sleep, nowSec, POLL_INTERVAL_MS, POLL_TIMEOUT_MS } from "./_base.js";
3
+ import { PROVIDER_MEDIA } from "../../providers/index.js";
23
4
 
24
- const BASE_URL = "https://api.bfl.ai/v1";
5
+ const BASE_URL = PROVIDER_MEDIA["black-forest-labs"]?.imageConfig?.baseUrl;
25
6
 
26
7
  export default {
27
8
  async: true,
@@ -1,35 +1,7 @@
1
- /**
2
- * Cloudflare AI Workers image generation adapter.
3
- *
4
- * Providers: cloudflare-ai
5
- * Auth: Bearer token via Authorization header
6
- * Requires providerSpecificData.accountId for endpoint construction.
7
- * Format: JSON body OR FormData (model-dependent) → sync base64 response
8
- * Polling: None (synchronous)
9
- *
10
- * Endpoint: https://api.cloudflare.com/client/v4/accounts/{accountId}/ai/run/{model}
11
- *
12
- * Supported request params:
13
- * @param {string} prompt - (required) Image description
14
- * @param {string} [size] - Parsed to width/height integers (e.g. "1024x1024")
15
- * @param {number} [seed] - Fixed seed
16
- * @param {number} [num_steps] - Diffusion steps
17
- * @param {number} [guidance] - CFG guidance scale
18
- * @param {string} [negative_prompt] - Elements to exclude
19
- * @param {string} [image_url] - Reference image for img2img (SD v1.5-img2img)
20
- * @param {string} [mask_image] - Mask image for inpainting (SD v1.5-inpainting)
21
- *
22
- * Body format:
23
- * - FLUX.2 Dev and similar multipart-only models → FormData
24
- * - All other models → JSON { prompt, width, height, ... }
25
- *
26
- * Response normalize:
27
- * - string → { data: [{ b64_json: result }] }
28
- * - { image: b64 } → { data: [{ b64_json: image }] }
29
- */
30
1
  import { nowSec, urlToBase64 } from "./_base.js";
2
+ import { PROVIDER_MEDIA } from "../../providers/index.js";
31
3
 
32
- const BASE_URL = "https://api.cloudflare.com/client/v4/accounts";
4
+ const BASE_URL = PROVIDER_MEDIA["cloudflare-ai"]?.imageConfig?.baseUrl;
33
5
 
34
6
  const MULTIPART_MODELS = new Set([
35
7
  "@cf/black-forest-labs/flux-2-dev",
@@ -1,27 +1,9 @@
1
- /**
2
- * OpenAI Codex (Responses API) image generation adapter.
3
- *
4
- * Providers: codex (ChatGPT Plus/Pro accounts via OAuth session)
5
- * Auth: Bearer session token + chatgpt-account-id header
6
- * Format: JSON body → SSE stream (parses image_generation_call delta events)
7
- * Polling: None (streaming SSE)
8
- *
9
- * Supported request params:
10
- * @param {string} prompt - (required) Image description
11
- * @param {string} [model="gpt-4o"] - Model ID ("-image" suffix is stripped automatically)
12
- * @param {string} [size="1024x1024"] - Dimensions: "1024x1024"|"1792x1024"|"1024x1792"|"1536x1024"|"1024x1536"
13
- * @param {string} [quality="auto"] - "low"|"medium"|"high"|"auto"
14
- * @param {string} [output_format="png"] - "png"|"jpeg"|"webp"
15
- * @param {string} [background="auto"] - "auto"|"transparent"|"opaque"
16
- * @param {string} [image_detail="high"] - "low"|"high"|"auto"
17
- * @param {string} [image] - Reference image URL or base64 data URI
18
- * @param {string[]} [images] - Multiple reference images
19
- */
20
1
  // Codex (ChatGPT Plus/Pro) image generation via Responses API + SSE
21
2
  import { randomUUID } from "node:crypto";
22
3
  import { nowSec } from "./_base.js";
4
+ import { PROVIDERS } from "../../config/providers.js";
23
5
 
24
- const CODEX_RESPONSES_URL = "https://chatgpt.com/backend-api/codex/responses";
6
+ const CODEX_RESPONSES_URL = PROVIDERS["codex"].baseUrl;
25
7
  const CODEX_USER_AGENT = "codex_cli_rs/0.136.0";
26
8
  const CODEX_VERSION = "0.136.0";
27
9
  const CODEX_ORIGINATOR = "codex_cli_rs";
@@ -1,24 +1,11 @@
1
- /**
2
- * ComfyUI local node-graph image generation adapter.
3
- *
4
- * Providers: comfyui (self-hosted instance)
5
- * Auth: None (unauthenticated local endpoint)
6
- * Format: JSON workflow prompt → async polling via /history endpoint
7
- * Polling: Yes — submits prompt then polls /history/{prompt_id}
8
- *
9
- * Supported request params:
10
- * @param {string} prompt - (required) Positive prompt text
11
- * @param {number} [n=1] - Number of images
12
- * @param {string} [size] - Dimensions → width/height in workflow
13
- * @param {number} [seed] - Fixed seed
14
- * @param {number} [num_steps] - Sampling steps
15
- *
16
- * Response normalize: downloads generated images and converts to base64.
17
- */
18
1
  // ComfyUI — local, noAuth (placeholder; full graph workflow not implemented)
2
+ import { PROVIDER_MEDIA } from "../../providers/index.js";
3
+
4
+ const BASE_URL = PROVIDER_MEDIA["comfyui"]?.imageConfig?.baseUrl;
5
+
19
6
  export default {
20
7
  noAuth: true,
21
- buildUrl: () => "http://localhost:8188",
8
+ buildUrl: () => BASE_URL,
22
9
  buildHeaders: () => ({ "Content-Type": "application/json" }),
23
10
  buildBody: (_model, body) => ({ prompt: body.prompt }),
24
11
  normalize: (responseBody) => responseBody,
@@ -1,28 +1,8 @@
1
- /**
2
- * Fal.ai asynchronous image generation adapter.
3
- *
4
- * Providers: fal-ai
5
- * Auth: Key {apiKey} via Authorization header (uses "Key" prefix, not "Bearer")
6
- * Format: JSON body → async queue submission + polling
7
- * Polling: Yes — submits to /runs, polls /requests/{id}/status, fetches /requests/{id}
8
- *
9
- * Supported request params:
10
- * @param {string} prompt - (required) Image description
11
- * @param {string} [model] - Model path (e.g. "fal-ai/flux/schnell")
12
- * @param {number} [n=1] - Number of images (num_images)
13
- * @param {string} [size="1024x1024"] - Maps to image_size aspect ratio: "1:1"|"16:9"|"9:16" etc.
14
- * @param {number} [seed] - Fixed seed for reproducibility
15
- * @param {number} [guidance] - Guidance scale (model-dependent)
16
- * @param {number} [num_steps] - Diffusion sampling steps
17
- * @param {string} [style] - Style preset (Recraft/Ideogram only)
18
- * @param {string} [image] - Reference image URL (img2img conditioning)
19
- *
20
- * Response normalize: maps images[] or image{} to { created, data: [{ url }] }.
21
- */
22
1
  // Fal.ai — async submit + queue polling
23
2
  import { sleep, nowSec, sizeToAspectRatio, POLL_INTERVAL_MS, POLL_TIMEOUT_MS } from "./_base.js";
3
+ import { PROVIDER_MEDIA } from "../../providers/index.js";
24
4
 
25
- const BASE_URL = "https://queue.fal.run";
5
+ const BASE_URL = PROVIDER_MEDIA["fal-ai"]?.imageConfig?.baseUrl;
26
6
 
27
7
  export default {
28
8
  async: true,
@@ -1,22 +1,8 @@
1
- /**
2
- * Google Gemini multimodal image generation adapter.
3
- *
4
- * Providers: gemini (via NanoBanana tier routing)
5
- * Auth: API key appended as ?key= query param
6
- * Format: JSON body → sync JSON response (generateContent / generateImage)
7
- * Polling: None (synchronous)
8
- *
9
- * Supported request params:
10
- * @param {string} prompt - (required) Image description text
11
- *
12
- * Notes:
13
- * - No size, quality, or style params are supported by the Gemini image endpoint.
14
- * - Response is normalized to { created, data: [{ b64_json, revised_prompt }] }.
15
- */
16
1
  // Google Gemini adapter (Nano Banana models)
17
2
  import { nowSec } from "./_base.js";
3
+ import { PROVIDER_MEDIA } from "../../providers/index.js";
18
4
 
19
- const BASE_URL = "https://generativelanguage.googleapis.com/v1beta/models";
5
+ const BASE_URL = PROVIDER_MEDIA["gemini"]?.imageConfig?.baseUrl;
20
6
 
21
7
  export default {
22
8
  buildUrl: (model, creds) => {
@@ -1,23 +1,8 @@
1
- /**
2
- * HuggingFace Inference API image generation adapter.
3
- *
4
- * Providers: huggingface
5
- * Auth: Bearer token via Authorization header (apiKey or accessToken)
6
- * Format: JSON body { inputs: prompt } → binary image response (PNG/JPEG)
7
- * Polling: None (synchronous, may queue on HF side)
8
- *
9
- * Supported request params:
10
- * @param {string} prompt - (required) Image description text
11
- *
12
- * Notes:
13
- * - Only "inputs" (prompt) is accepted by the HF Inference endpoint.
14
- * - No size, quality, style, or other params are passed through.
15
- * - Response normalize: converts raw binary image to base64 data URI.
16
- */
17
1
  // HuggingFace Inference API — returns binary image
18
2
  import { nowSec } from "./_base.js";
3
+ import { PROVIDER_MEDIA } from "../../providers/index.js";
19
4
 
20
- const BASE_URL = "https://api-inference.huggingface.co/models";
5
+ const BASE_URL = PROVIDER_MEDIA["huggingface"]?.imageConfig?.baseUrl;
21
6
 
22
7
  export default {
23
8
  buildUrl: (model) => `${BASE_URL}/${model}`,
@@ -11,14 +11,14 @@ import stabilityAi from "./stabilityAi.js";
11
11
  import blackForestLabs from "./blackForestLabs.js";
12
12
  import runwayml from "./runwayml.js";
13
13
  import cloudflareAi from "./cloudflareAi.js";
14
- import leonardo from "./leonardo.js";
15
- import weavy from "./weavy.js";
14
+ import antigravity from "./antigravity.js";
16
15
 
17
16
  const ADAPTERS = {
18
17
  openai: createOpenAIAdapter("openai"),
19
18
  minimax: createOpenAIAdapter("minimax"),
20
19
  openrouter: createOpenAIAdapter("openrouter"),
21
20
  recraft: createOpenAIAdapter("recraft"),
21
+ "vercel-ai-gateway": createOpenAIAdapter("vercel-ai-gateway"),
22
22
  xai: createOpenAIAdapter("xai"),
23
23
  gemini,
24
24
  codex,
@@ -26,13 +26,12 @@ const ADAPTERS = {
26
26
  comfyui,
27
27
  huggingface,
28
28
  nanobanana,
29
+ antigravity,
29
30
  "fal-ai": falAi,
30
31
  "stability-ai": stabilityAi,
31
32
  "black-forest-labs": blackForestLabs,
32
33
  runwayml,
33
34
  "cloudflare-ai": cloudflareAi,
34
- leonardo,
35
- weavy,
36
35
  };
37
36
 
38
37
  export function getImageAdapter(provider) {
@@ -34,7 +34,7 @@ import { randomBytes } from "crypto";
34
34
  // Falls back to empty object if DB not available (e.g., first boot).
35
35
  async function getLeonardoAdminConfig() {
36
36
  try {
37
- const { getAdapter } = await import('../../../../dist/lib/db/driver.js');
37
+ const { getAdapter } = await import('../../../dist/lib/db/driver.js');
38
38
  const db = await getAdapter();
39
39
  const row = db.get(`SELECT value FROM kv WHERE scope = 'leonardo' AND key = 'admin_config'`);
40
40
  if (!row?.value) return null;
@@ -1,29 +1,10 @@
1
- /**
2
- * NanoBanana image generation adapter.
3
- *
4
- * Providers: nanobanana
5
- * Auth: Bearer token (apiKey or accessToken)
6
- * Format: JSON body → async polling via task status endpoint
7
- * Polling: Yes — polls until resultImageUrl is available
8
- *
9
- * Supported request params:
10
- * @param {string} prompt - (required) Image description
11
- * @param {number} [n=1] - Number of images (numImages)
12
- * @param {string} [size="1024x1024"] - Maps to aspect ratio: "1:1"|"9:16"|"16:9"|"4:3"|"3:2"|"2:3"
13
- * @param {string} [image] - Reference image URL → enables IMAGETOIAMGE mode
14
- * @param {string[]} [images] - Multiple reference image URLs
15
- *
16
- * Request type:
17
- * - No image → type: "TEXTTOIAMGE"
18
- * - image/images provided → type: "IMAGETOIAMGE"
19
- *
20
- * Response normalize: extracts resultImageUrl (falls back to originImageUrl).
21
- */
22
1
  // NanoBanana API — async submit + poll record-info
23
2
  import { sleep, nowSec, sizeToAspectRatio, POLL_INTERVAL_MS, POLL_TIMEOUT_MS } from "./_base.js";
3
+ import { PROVIDER_MEDIA } from "../../providers/index.js";
24
4
 
25
- const SUBMIT_URL = "https://api.nanobananaapi.ai/api/v1/nanobanana/generate";
26
- const POLL_BASE = "https://api.nanobananaapi.ai/api/v1/nanobanana/record-info";
5
+ const IMG_CFG = PROVIDER_MEDIA["nanobanana"]?.imageConfig || {};
6
+ const SUBMIT_URL = IMG_CFG.baseUrl;
7
+ const POLL_BASE = IMG_CFG.pollUrl;
27
8
 
28
9
  export default {
29
10
  async: true,
@@ -1,60 +1,32 @@
1
- /**
2
- * OpenAI-compatible image generation adapter.
3
- *
4
- * Providers: openai | minimax | openrouter | recraft | xai
5
- * Auth: Bearer token via Authorization header (apiKey or accessToken)
6
- * Format: JSON body → sync JSON response
7
- * Polling: None (synchronous)
8
- *
9
- * Supported request params:
10
- * @param {string} prompt - (required) Image description
11
- * @param {string} [model] - Model ID (set by caller)
12
- * @param {number} [n=1] - Number of images (1–10 for DALL-E 2; 1 for DALL-E 3/GPT Image 1)
13
- * @param {string} [size="1024x1024"] - Dimensions: "256x256"|"512x512"|"1024x1024"|"1792x1024"|"1024x1792"
14
- * @param {string} [quality="standard"] - "standard"|"hd"|"low"|"medium"|"high"|"auto"
15
- * @param {string} [style] - DALL-E 3 only: "vivid"|"natural"
16
- * @param {string} [response_format="url"] - "url"|"b64_json"
17
- * @param {string} [output_format] - GPT Image 1 only: "png"|"jpeg"|"webp"
18
- * @param {string} [background] - GPT Image 1 only: "auto"|"transparent"|"opaque"
19
- *
20
- * xAI note: only prompt, model, n, response_format are forwarded.
21
- */
22
1
  // OpenAI-compatible adapter (used by openai, minimax, openrouter, recraft)
2
+ import { PROVIDER_MEDIA } from "../../providers/index.js";
23
3
 
24
- const ENDPOINTS = {
25
- openai: "https://api.openai.com/v1/images/generations",
26
- minimax: "https://api.minimaxi.com/v1/images/generations",
27
- openrouter: "https://openrouter.ai/api/v1/images/generations",
28
- recraft: "https://external.api.recraft.ai/v1/images/generations",
29
- xai: "https://api.x.ai/v1/images/generations",
30
- };
4
+ const imageCfg = (id) => PROVIDER_MEDIA[id]?.imageConfig || {};
5
+ const imageUrl = (id) => imageCfg(id).baseUrl;
31
6
 
32
7
  export default function createOpenAIAdapter(providerId) {
8
+ const cfg = imageCfg(providerId);
33
9
  return {
34
- buildUrl: () => ENDPOINTS[providerId],
10
+ buildUrl: () => imageUrl(providerId),
35
11
  buildHeaders: (creds) => {
36
- const headers = { "Content-Type": "application/json" };
12
+ const headers = { "Content-Type": "application/json", ...(cfg.headers || {}) };
37
13
  const key = creds?.apiKey || creds?.accessToken;
38
14
  if (key) headers["Authorization"] = `Bearer ${key}`;
39
- if (providerId === "openrouter") {
40
- headers["HTTP-Referer"] = "https://endpoint-proxy.local";
41
- headers["X-Title"] = "Endpoint Proxy";
42
- }
43
15
  return headers;
44
16
  },
45
17
  buildBody: (model, body) => {
46
18
  const { prompt, n = 1, size = "1024x1024", quality, style, response_format } = body;
47
- // xAI only accepts prompt, model, n, response_format
48
- if (providerId === "xai") {
49
- const req = { model, prompt, n };
50
- if (response_format) req.response_format = response_format;
19
+ const full = { model, prompt, n, size };
20
+ if (quality) full.quality = quality;
21
+ if (style) full.style = style;
22
+ if (response_format) full.response_format = response_format;
23
+ // bodyFields whitelist (e.g. xAI accepts only model/prompt/n/response_format)
24
+ if (Array.isArray(cfg.bodyFields)) {
25
+ const req = {};
26
+ for (const f of cfg.bodyFields) if (full[f] !== undefined) req[f] = full[f];
51
27
  return req;
52
28
  }
53
- const req = { model, prompt, n, size };
54
- if (quality) req.quality = quality;
55
- if (style) req.style = style;
56
- if (response_format) req.response_format = response_format;
57
- return req;
29
+ return full;
58
30
  },
59
31
  normalize: (responseBody) => responseBody,
60
32
  };
@@ -1,32 +1,8 @@
1
- /**
2
- * RunwayML image and video generation adapter.
3
- *
4
- * Providers: runwayml
5
- * Auth: Bearer token + X-Runway-Version header
6
- * Format: JSON body → async polling
7
- * Polling: Yes — polls task ID until status == "SUCCEEDED"
8
- *
9
- * Model routing:
10
- * - "*_image*" model IDs → POST /text_to_image (image generation)
11
- * - all others → POST /image_to_video (video generation)
12
- *
13
- * Image model params:
14
- * @param {string} prompt - (required) Image description (sent as promptText)
15
- * @param {string} [size] - Maps to ratio: "1:1"|"16:9"|"9:16" etc.
16
- * @param {string} [image] - Reference image URL (referenceImages[])
17
- *
18
- * Video model params:
19
- * @param {string} prompt - (required) Video description (promptText)
20
- * @param {string} [image] - Start frame URL (promptImage)
21
- * @param {number} [duration=5] - Video duration in seconds
22
- * @param {string} [resolution] - "720p"|"1080p"
23
- *
24
- * Response normalize: output[] → { created, data: [{ url }] }.
25
- */
26
1
  // Runway ML — async submit + /tasks/{id} polling
27
2
  import { sleep, nowSec, sizeToAspectRatio, POLL_INTERVAL_MS, POLL_TIMEOUT_MS } from "./_base.js";
3
+ import { PROVIDER_MEDIA } from "../../providers/index.js";
28
4
 
29
- const BASE_URL = "https://api.dev.runwayml.com/v1";
5
+ const BASE_URL = PROVIDER_MEDIA["runwayml"]?.imageConfig?.baseUrl;
30
6
 
31
7
  export default {
32
8
  async: true,
@@ -1,28 +1,12 @@
1
- /**
2
- * Stable Diffusion WebUI (Automatic1111) local adapter.
3
- *
4
- * Providers: sdwebui (self-hosted instance)
5
- * Auth: Optional HTTP Basic auth (username/password)
6
- * Format: JSON body → sync JSON response
7
- * Polling: None (synchronous, but can be slow)
8
- *
9
- * Supported request params:
10
- * @param {string} prompt - (required) Positive prompt
11
- * @param {number} [n=1] - Number of images (batch_size)
12
- * @param {string} [size="512x512"] - Dimensions e.g. "512x512", "768x768" → width/height
13
- * @param {string} [negative_prompt] - Tokens to exclude
14
- * @param {number} [seed] - Fixed seed (-1 = random)
15
- * @param {number} [guidance=7] - CFG scale
16
- * @param {number} [num_steps=20] - Sampling steps
17
- *
18
- * Response normalize: extracts images[0] → { created, data: [{ b64_json }] }.
19
- */
20
1
  // SD WebUI (AUTOMATIC1111) — local, noAuth
21
2
  import { nowSec } from "./_base.js";
3
+ import { PROVIDER_MEDIA } from "../../providers/index.js";
4
+
5
+ const BASE_URL = PROVIDER_MEDIA["sdwebui"]?.imageConfig?.baseUrl;
22
6
 
23
7
  export default {
24
8
  noAuth: true,
25
- buildUrl: () => "http://localhost:7860/sdapi/v1/txt2img",
9
+ buildUrl: () => BASE_URL,
26
10
  buildHeaders: () => ({ "Content-Type": "application/json" }),
27
11
  buildBody: (_model, body) => {
28
12
  const { prompt, n = 1, size = "1024x1024" } = body;