@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.
- package/dist/lib/headroom/detect.js +97 -7
- package/dist/lib/headroom/process.js +136 -4
- package/dist/open-sse/config/appConstants.js +23 -79
- package/dist/open-sse/config/cliFingerprints.js +1 -1
- package/dist/open-sse/config/errorConfig.js +0 -11
- package/dist/open-sse/config/grokCli.js +10 -0
- package/dist/open-sse/config/kiroConstants.js +99 -46
- package/dist/open-sse/config/runtimeConfig.js +2 -0
- package/dist/open-sse/config/ttsModels.js +2 -0
- package/dist/open-sse/executors/antigravity.js +250 -164
- package/dist/open-sse/executors/base.js +16 -11
- package/dist/open-sse/executors/codex.js +269 -1108
- package/dist/open-sse/executors/commandCode.js +1 -1
- package/dist/open-sse/executors/commandcode.js +10 -4
- package/dist/open-sse/executors/cursor.js +96 -203
- package/dist/open-sse/executors/default.js +146 -244
- package/dist/open-sse/executors/github.js +128 -73
- package/dist/open-sse/executors/grok-cli.js +527 -94
- package/dist/open-sse/executors/grok-web.js +5 -7
- package/dist/open-sse/executors/index.js +12 -0
- package/dist/open-sse/executors/kiro.js +150 -61
- package/dist/open-sse/executors/opencode-go.js +12 -4
- package/dist/open-sse/executors/opencode.js +1 -1
- package/dist/open-sse/executors/perplexity-web.js +20 -96
- package/dist/open-sse/executors/qoder.js +28 -18
- package/dist/open-sse/executors/vertex.js +53 -7
- package/dist/open-sse/executors/xiaomi-tokenplan.js +6 -5
- package/dist/open-sse/handlers/chatCore/nonStreamingHandler.js +97 -85
- package/dist/open-sse/handlers/chatCore/requestDetail.js +32 -8
- package/dist/open-sse/handlers/chatCore/sseToJsonHandler.js +13 -7
- package/dist/open-sse/handlers/chatCore/streamingHandler.js +74 -25
- package/dist/open-sse/handlers/chatCore.js +35 -41
- package/dist/open-sse/handlers/embeddingProviders/index.js +1 -0
- package/dist/open-sse/handlers/embeddingProviders/openai.js +8 -16
- package/dist/open-sse/handlers/imageProviders/blackForestLabs.js +2 -21
- package/dist/open-sse/handlers/imageProviders/cloudflareAi.js +2 -30
- package/dist/open-sse/handlers/imageProviders/codex.js +2 -20
- package/dist/open-sse/handlers/imageProviders/comfyui.js +5 -18
- package/dist/open-sse/handlers/imageProviders/falAi.js +2 -22
- package/dist/open-sse/handlers/imageProviders/gemini.js +2 -16
- package/dist/open-sse/handlers/imageProviders/huggingface.js +2 -17
- package/dist/open-sse/handlers/imageProviders/index.js +3 -4
- package/dist/open-sse/handlers/imageProviders/leonardo.js +1 -1
- package/dist/open-sse/handlers/imageProviders/nanobanana.js +4 -23
- package/dist/open-sse/handlers/imageProviders/openai.js +15 -43
- package/dist/open-sse/handlers/imageProviders/runwayml.js +2 -26
- package/dist/open-sse/handlers/imageProviders/sdwebui.js +4 -20
- package/dist/open-sse/handlers/imageProviders/stabilityAi.js +2 -26
- package/dist/open-sse/handlers/imageProviders/weavy.js +1 -1
- package/dist/open-sse/handlers/search/chatSearch.js +60 -14
- package/dist/open-sse/handlers/ttsProviders/gemini.js +14 -3
- package/dist/open-sse/handlers/ttsProviders/index.js +4 -2
- package/dist/open-sse/handlers/ttsProviders/openai.js +4 -1
- package/dist/open-sse/handlers/ttsProviders/openrouter.js +7 -4
- package/dist/open-sse/handlers/videoCore.js +166 -0
- package/dist/open-sse/handlers/videoProviders/weavy.js +1 -1
- package/dist/open-sse/mcp-server/catalog.js +1 -1
- package/dist/open-sse/mcp-server/server.js +2 -2
- package/dist/open-sse/mcp-server/tools/advancedTools.js +2 -2
- package/dist/open-sse/mcp-server/tools/agentSkillTools.js +1 -1
- package/dist/open-sse/mcp-server/tools/compressionTools.js +4 -4
- package/dist/open-sse/mcp-server/tools/gamificationTools.js +10 -10
- package/dist/open-sse/mcp-server/tools/githubSkillTools.js +1 -1
- package/dist/open-sse/mcp-server/tools/memoryTools.js +3 -3
- package/dist/open-sse/mcp-server/tools/notionTools.js +2 -2
- package/dist/open-sse/mcp-server/tools/obsidianTools.js +2 -2
- package/dist/open-sse/mcp-server/tools/pickFastestModel.js +1 -1
- package/dist/open-sse/mcp-server/tools/pluginTools.js +4 -4
- package/dist/open-sse/mcp-server/tools/skillTools.js +2 -2
- package/dist/open-sse/providers/capabilities.js +24 -4
- package/dist/open-sse/providers/registry/alicode-intl.js +1 -1
- package/dist/open-sse/providers/registry/anthropic.js +1 -8
- package/dist/open-sse/providers/registry/codex.js +0 -9
- package/dist/open-sse/providers/registry/cohere.js +0 -2
- package/dist/open-sse/providers/registry/gemini.js +0 -2
- package/dist/open-sse/providers/registry/github.js +9 -6
- package/dist/open-sse/providers/registry/grok-cli.js +28 -18
- package/dist/open-sse/providers/registry/index.js +74 -80
- package/dist/open-sse/providers/registry/kiro.js +12 -0
- package/dist/open-sse/providers/registry/mistral.js +0 -3
- package/dist/open-sse/providers/registry/openai.js +0 -3
- package/dist/open-sse/providers/registry/perplexity.js +0 -2
- package/dist/open-sse/providers/registry/xai.js +5 -3
- package/dist/open-sse/rtk/autodetect.js +10 -2
- package/dist/open-sse/rtk/caveman.js +2 -93
- package/dist/open-sse/rtk/cavemanPrompts.js +34 -2
- package/dist/open-sse/rtk/constants.js +7 -2
- package/dist/open-sse/rtk/headroom.js +133 -0
- package/dist/open-sse/rtk/ponytail.js +1 -1
- package/dist/open-sse/rtk/registry.js +2 -0
- package/dist/open-sse/services/accountFallback.js +0 -108
- package/dist/open-sse/services/combo/quotaExhaustionCutoff.js +2 -2
- package/dist/open-sse/services/combo/quotaShareStrategy.js +1 -1
- package/dist/open-sse/services/combo/resolveAutoStrategy.js +1 -1
- package/dist/open-sse/services/combo/sessionStickiness.js +1 -1
- package/dist/open-sse/services/combo/targetSorters.js +2 -2
- package/dist/open-sse/services/combo/validateQuality.js +1 -1
- package/dist/open-sse/services/comboConfig.js +1 -1
- package/dist/open-sse/services/emergencyFallback.js +1 -1
- package/dist/open-sse/services/grokCliModels.js +127 -0
- package/dist/open-sse/services/model.js +7 -1
- package/dist/open-sse/services/provider.js +1 -1
- package/dist/open-sse/services/proxyAutoSelector.js +1 -1
- package/dist/open-sse/services/tokenRefresh/providers.js +3 -3
- package/dist/open-sse/services/usage/codex.js +148 -214
- package/dist/open-sse/services/usage/grok-cli.js +61 -7
- package/dist/open-sse/services/usage/misc.js +0 -19
- package/dist/open-sse/services/usage.js +0 -2
- package/dist/open-sse/translator/concerns/paramSupport.js +2 -2
- package/dist/open-sse/translator/concerns/thinkingUnified.js +6 -0
- package/dist/open-sse/translator/index.js +97 -59
- package/dist/open-sse/translator/request/claude-to-kiro.js +67 -40
- package/dist/open-sse/translator/request/openai-responses.js +1 -0
- package/dist/open-sse/translator/request/openai-to-commandcode.js +0 -4
- package/dist/open-sse/translator/request/openai-to-kiro.js +49 -20
- package/dist/open-sse/translator/response/commandcode-to-openai.js +0 -4
- package/dist/open-sse/utils/bypassHandler.js +18 -3
- package/dist/open-sse/utils/claudeCloaking.js +15 -5
- package/dist/open-sse/utils/cursorImages.js +1 -1
- package/dist/open-sse/utils/error.js +0 -17
- package/dist/open-sse/utils/keepaliveThreshold.js +4 -4
- package/dist/open-sse/utils/kiroSessionReplay.js +125 -0
- package/dist/open-sse/utils/noThinkingAlias.js +1 -1
- package/dist/open-sse/utils/proxyFetch.js +0 -1
- package/dist/open-sse/utils/reasoningContentInjector.js +4 -7
- package/dist/open-sse/utils/responsesStatePolicy.js +1 -1
- package/dist/open-sse/utils/responsesStreamHelpers.js +1 -0
- package/dist/open-sse/utils/sessionManager.js +49 -22
- package/dist/open-sse/utils/stream.js +54 -77
- package/dist/open-sse/utils/streamHandler.js +19 -15
- package/dist/open-sse/utils/streamHelpers.js +2 -17
- package/dist/open-sse/utils/usageTracking.js +103 -12
- package/dist/routes/headroom/extras/route.js +58 -0
- package/dist/routes/headroom/restart/route.js +33 -0
- package/open-sse/config/appConstants.js +23 -79
- package/open-sse/config/errorConfig.js +0 -11
- package/open-sse/config/grokCli.js +10 -0
- package/open-sse/config/kiroConstants.js +99 -46
- package/open-sse/config/runtimeConfig.js +2 -0
- package/open-sse/config/ttsModels.js +2 -0
- package/open-sse/executors/antigravity.js +250 -164
- package/open-sse/executors/base.js +16 -11
- package/open-sse/executors/codex.js +269 -1108
- package/open-sse/executors/commandcode.js +10 -4
- package/open-sse/executors/cursor.js +96 -203
- package/open-sse/executors/default.js +146 -244
- package/open-sse/executors/github.js +128 -73
- package/open-sse/executors/grok-cli.js +527 -94
- package/open-sse/executors/grok-web.js +5 -7
- package/open-sse/executors/index.js +12 -0
- package/open-sse/executors/kiro.js +150 -61
- package/open-sse/executors/opencode-go.js +12 -4
- package/open-sse/executors/opencode.js +1 -1
- package/open-sse/executors/perplexity-web.js +20 -96
- package/open-sse/executors/qoder.js +28 -18
- package/open-sse/executors/vertex.js +53 -7
- package/open-sse/executors/xiaomi-tokenplan.js +6 -5
- package/open-sse/handlers/chatCore/nonStreamingHandler.js +97 -85
- package/open-sse/handlers/chatCore/requestDetail.js +32 -8
- package/open-sse/handlers/chatCore/sseToJsonHandler.js +13 -7
- package/open-sse/handlers/chatCore/streamingHandler.js +74 -25
- package/open-sse/handlers/chatCore.js +35 -41
- package/open-sse/handlers/embeddingProviders/index.js +1 -0
- package/open-sse/handlers/embeddingProviders/openai.js +8 -16
- package/open-sse/handlers/imageProviders/blackForestLabs.js +2 -21
- package/open-sse/handlers/imageProviders/cloudflareAi.js +2 -30
- package/open-sse/handlers/imageProviders/codex.js +2 -20
- package/open-sse/handlers/imageProviders/comfyui.js +5 -18
- package/open-sse/handlers/imageProviders/falAi.js +2 -22
- package/open-sse/handlers/imageProviders/gemini.js +2 -16
- package/open-sse/handlers/imageProviders/huggingface.js +2 -17
- package/open-sse/handlers/imageProviders/index.js +3 -4
- package/open-sse/handlers/imageProviders/leonardo.js +1 -1
- package/open-sse/handlers/imageProviders/nanobanana.js +4 -23
- package/open-sse/handlers/imageProviders/openai.js +15 -43
- package/open-sse/handlers/imageProviders/runwayml.js +2 -26
- package/open-sse/handlers/imageProviders/sdwebui.js +4 -20
- package/open-sse/handlers/imageProviders/stabilityAi.js +2 -26
- package/open-sse/handlers/imageProviders/weavy.js +1 -1
- package/open-sse/handlers/search/chatSearch.js +60 -14
- package/open-sse/handlers/ttsProviders/gemini.js +14 -3
- package/open-sse/handlers/ttsProviders/index.js +4 -2
- package/open-sse/handlers/ttsProviders/openai.js +4 -1
- package/open-sse/handlers/ttsProviders/openrouter.js +7 -4
- package/open-sse/handlers/videoCore.js +166 -0
- package/open-sse/handlers/videoProviders/weavy.js +1 -1
- package/open-sse/mcp-server/audit.js +1 -1
- package/open-sse/mcp-server/catalog.js +2 -2
- package/open-sse/mcp-server/descriptionCompressor.js +1 -1
- package/open-sse/mcp-server/mcpCallerIdentity.js +1 -1
- package/open-sse/mcp-server/schemas/tools.js +1 -1
- package/open-sse/mcp-server/server.js +4 -4
- package/open-sse/mcp-server/tools/advancedTools.js +5 -5
- package/open-sse/mcp-server/tools/agentSkillTools.js +1 -1
- package/open-sse/mcp-server/tools/compressionTools.js +4 -4
- package/open-sse/mcp-server/tools/gamificationTools.js +10 -10
- package/open-sse/mcp-server/tools/githubSkillTools.js +1 -1
- package/open-sse/mcp-server/tools/memoryTools.js +3 -3
- package/open-sse/mcp-server/tools/notionTools.js +2 -2
- package/open-sse/mcp-server/tools/obsidianTools.js +2 -2
- package/open-sse/mcp-server/tools/pickFastestModel.js +3 -3
- package/open-sse/mcp-server/tools/pluginTools.js +4 -4
- package/open-sse/mcp-server/tools/skillTools.js +2 -2
- package/open-sse/providers/capabilities.js +24 -4
- package/open-sse/providers/registry/alicode-intl.js +1 -1
- package/open-sse/providers/registry/anthropic.js +1 -8
- package/open-sse/providers/registry/codex.js +0 -9
- package/open-sse/providers/registry/cohere.js +0 -2
- package/open-sse/providers/registry/gemini.js +0 -2
- package/open-sse/providers/registry/github.js +9 -6
- package/open-sse/providers/registry/grok-cli.js +28 -18
- package/open-sse/providers/registry/index.js +74 -80
- package/open-sse/providers/registry/kiro.js +12 -0
- package/open-sse/providers/registry/mistral.js +0 -3
- package/open-sse/providers/registry/openai.js +0 -3
- package/open-sse/providers/registry/perplexity.js +0 -2
- package/open-sse/providers/registry/xai.js +5 -3
- package/open-sse/rtk/autodetect.js +10 -2
- package/open-sse/rtk/caveman.js +2 -93
- package/open-sse/rtk/cavemanPrompts.js +34 -2
- package/open-sse/rtk/constants.js +7 -2
- package/open-sse/rtk/headroom.js +133 -0
- package/open-sse/rtk/ponytail.js +1 -1
- package/open-sse/rtk/registry.js +2 -0
- package/open-sse/services/accountFallback.js +0 -108
- package/open-sse/services/combo/quotaExhaustionCutoff.js +2 -2
- package/open-sse/services/combo/quotaShareStrategy.js +1 -1
- package/open-sse/services/combo/resolveAutoStrategy.js +1 -1
- package/open-sse/services/combo/sessionStickiness.js +1 -1
- package/open-sse/services/combo/shadowRouting.js +1 -1
- package/open-sse/services/combo/targetSorters.js +4 -4
- package/open-sse/services/combo/validateQuality.js +1 -1
- package/open-sse/services/evalRouting.js +1 -1
- package/open-sse/services/grokCliModels.js +127 -0
- package/open-sse/services/model.js +7 -1
- package/open-sse/services/modelCapabilities.js +1 -1
- package/open-sse/services/modelFamilyFallback.js +1 -1
- package/open-sse/services/provider.js +1 -1
- package/open-sse/services/providerCooldownTracker.js +1 -1
- package/open-sse/services/rateLimitManager.js +1 -1
- package/open-sse/services/tokenRefresh/providers.js +3 -3
- package/open-sse/services/usage/codex.js +148 -214
- package/open-sse/services/usage/grok-cli.js +61 -7
- package/open-sse/services/usage/misc.js +0 -19
- package/open-sse/services/usage.js +0 -2
- package/open-sse/translator/concerns/paramSupport.js +2 -2
- package/open-sse/translator/concerns/thinkingUnified.js +6 -0
- package/open-sse/translator/index.js +97 -59
- package/open-sse/translator/request/claude-to-kiro.js +67 -40
- package/open-sse/translator/request/openai-responses.js +1 -0
- package/open-sse/translator/request/openai-to-commandcode.js +0 -4
- package/open-sse/translator/request/openai-to-kiro.js +49 -20
- package/open-sse/translator/response/commandcode-to-openai.js +0 -4
- package/open-sse/utils/bypassHandler.js +18 -3
- package/open-sse/utils/claudeCloaking.js +15 -5
- package/open-sse/utils/error.js +0 -17
- package/open-sse/utils/kiroSessionReplay.js +125 -0
- package/open-sse/utils/logger.js +1 -1
- package/open-sse/utils/proxyFetch.js +0 -1
- package/open-sse/utils/reasoningContentInjector.js +4 -7
- package/open-sse/utils/responsesStreamHelpers.js +1 -0
- package/open-sse/utils/sessionManager.js +49 -22
- package/open-sse/utils/stream.js +54 -77
- package/open-sse/utils/streamHandler.js +19 -15
- package/open-sse/utils/streamHelpers.js +2 -17
- package/open-sse/utils/usageTracking.js +103 -12
- package/package.json +4 -7
- package/public/assets/EndpointPageClient.C2WMTYy0.js +6 -0
- package/public/assets/{Loading.Bj-WGl4k.js → Loading.BHPtQ9vj.js} +1 -1
- package/public/assets/{NoAuthProxyCard.qAv57b-0.js → NoAuthProxyCard.BDcXaWvM.js} +1 -1
- package/public/assets/index.Be3gbrBl.js +89 -0
- package/public/assets/index.COMgQZYj.css +1 -0
- package/public/assets/{page.CbkENBd5.js → page.-lpNgYAw.js} +1 -1
- package/public/assets/{page.CssmrzTT.js → page.11hpNKmq.js} +1 -1
- package/public/assets/{page.C72FTTJr.js → page.B-LxsnqU.js} +1 -1
- package/public/assets/{page.sOFOrxqq.js → page.B-dzeIUC.js} +1 -1
- package/public/assets/{page.CsxWmPoI.js → page.B-nBR75u.js} +1 -1
- package/public/assets/{page.Dx_GRRdT.js → page.B3QqvLep.js} +1 -1
- package/public/assets/{page.DPyOkPVo.js → page.B8xdkCWA.js} +1 -1
- package/public/assets/{page.DUI8kqOY.js → page.BFb7yUd8.js} +1 -1
- package/public/assets/page.BbPPdoas.js +1 -0
- package/public/assets/page.BdS20a1O.js +1 -0
- package/public/assets/{page.DibhF7f-.js → page.BfmI9KYe.js} +1 -1
- package/public/assets/{page.DX4Nno6M.js → page.BgGJovOg.js} +1 -1
- package/public/assets/{page.BnmTC5jG.js → page.C0gBvR4O.js} +1 -1
- package/public/assets/{page.D5gj98Oe.js → page.C6bYizL7.js} +1 -1
- package/public/assets/{page.vla5Mzki.js → page.C8sLEMa6.js} +1 -1
- package/public/assets/{page.CXd_R9yU.js → page.CCNsZBXp.js} +1 -1
- package/public/assets/{page.CQlVGoXg.js → page.CF_YSLwP.js} +1 -1
- package/public/assets/{page.BbO1pspY.js → page.CPTtRDxw.js} +1 -1
- package/public/assets/{page.D1oKew1j.js → page.CdMmlUEm.js} +1 -1
- package/public/assets/{page.DxMDTbSx.js → page.Cged1bOZ.js} +1 -1
- package/public/assets/{page.Cj5h09Zo.js → page.Ch647dVk.js} +1 -1
- package/public/assets/{page.DVIHRbxB.js → page.CpvXDkQF.js} +1 -1
- package/public/assets/{page.i4KDuWcM.js → page.CrBl7f8N.js} +1 -1
- package/public/assets/{page.BSLJ4tx5.js → page.CrP7niA2.js} +1 -1
- package/public/assets/{page.CnTop8Zt.js → page.CvUFZzXr.js} +1 -1
- package/public/assets/{page.O2ddJYoT.js → page.CyUqJPmx.js} +1 -1
- package/public/assets/{page.DBhu4Arl.js → page.D8Rp8fFR.js} +1 -1
- package/public/assets/{page.CPZav1_c.js → page.Df9qtrdG.js} +1 -1
- package/public/assets/{page.Qkkv8roc.js → page.DiL4Gwqe.js} +1 -1
- package/public/assets/{page.BdmJ3yY3.js → page.Dl1apZE2.js} +1 -1
- package/public/assets/{page.1qjqvrwX.js → page.HV0w1d5C.js} +1 -1
- package/public/assets/{page.ChX1NqmC.js → page.N1x4YL8_.js} +1 -1
- package/public/assets/{page.Dh5f0XJC.js → page.P2Ny5veR.js} +1 -1
- package/public/assets/{page.CSs3-gdt.js → page.fOOCr18J.js} +1 -1
- package/public/assets/{page.Ir7KvKcF.js → page.sUIPWIiF.js} +1 -1
- package/public/assets/{page.CzlQTyAL.js → page.tE7PpWYW.js} +1 -1
- package/public/assets/{page.DzZLqI5Q.js → page.uziaGZsT.js} +1 -1
- package/public/index.html +2 -2
- package/public/assets/EndpointPageClient.LyNNvZ4z.js +0 -6
- package/public/assets/index.BuPfZebu.css +0 -1
- package/public/assets/index.CShjRV_B.js +0 -89
- package/public/assets/page.DD_czjjP.js +0 -1
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import {
|
|
2
|
+
GROK_CLI_BASE_URL,
|
|
3
|
+
GROK_CLI_CLIENT_IDENTIFIER,
|
|
4
|
+
GROK_CLI_MODEL,
|
|
5
|
+
GROK_CLI_USER_AGENT,
|
|
6
|
+
GROK_CLI_VERSION,
|
|
7
|
+
} from "../config/grokCli.js";
|
|
8
|
+
import { refreshProviderCredentials } from "./oauthCredentialManager.js";
|
|
9
|
+
import { proxyAwareFetch } from "../utils/proxyFetch.js";
|
|
10
|
+
|
|
11
|
+
const MODELS_URL = `${GROK_CLI_BASE_URL}/models`;
|
|
12
|
+
|
|
13
|
+
function modelEntries(data) {
|
|
14
|
+
const value = Array.isArray(data) ? data : data?.data ?? data?.models ?? data?.results ?? [];
|
|
15
|
+
if (Array.isArray(value)) return value.map((item) => [null, item]);
|
|
16
|
+
if (value && typeof value === "object") return Object.entries(value);
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function parseGrokCliModels(data) {
|
|
21
|
+
const seen = new Set();
|
|
22
|
+
const models = [];
|
|
23
|
+
|
|
24
|
+
for (const [key, raw] of modelEntries(data)) {
|
|
25
|
+
const item = typeof raw === "string" ? { id: raw } : raw;
|
|
26
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) continue;
|
|
27
|
+
const id = String(
|
|
28
|
+
item.id ?? item.model_id ?? item.modelId ?? item.model ?? item.slug ?? key ?? item.name ?? "",
|
|
29
|
+
).trim();
|
|
30
|
+
if (!id || seen.has(id)) continue;
|
|
31
|
+
seen.add(id);
|
|
32
|
+
|
|
33
|
+
const model = {
|
|
34
|
+
...item,
|
|
35
|
+
id,
|
|
36
|
+
name: item.display_name ?? item.displayName ?? item.name ?? id,
|
|
37
|
+
};
|
|
38
|
+
const contextLength = Number(
|
|
39
|
+
item.context_length ?? item.contextLength ?? item.context_window ?? item.contextWindow,
|
|
40
|
+
);
|
|
41
|
+
const maxOutputTokens = Number(item.max_output_tokens ?? item.maxOutputTokens);
|
|
42
|
+
if (Number.isFinite(contextLength) && contextLength > 0) model.contextLength = contextLength;
|
|
43
|
+
if (Number.isFinite(maxOutputTokens) && maxOutputTokens > 0) {
|
|
44
|
+
model.maxOutputTokens = maxOutputTokens;
|
|
45
|
+
}
|
|
46
|
+
if (id === GROK_CLI_MODEL) {
|
|
47
|
+
model.contextLength ||= 500000;
|
|
48
|
+
model.maxOutputTokens ||= 64000;
|
|
49
|
+
}
|
|
50
|
+
models.push(model);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return models;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function buildHeaders(accessToken, providerSpecificData = {}) {
|
|
57
|
+
const headers = {
|
|
58
|
+
Authorization: `Bearer ${accessToken}`,
|
|
59
|
+
Accept: "application/json",
|
|
60
|
+
"User-Agent": GROK_CLI_USER_AGENT,
|
|
61
|
+
"x-xai-token-auth": "xai-grok-cli",
|
|
62
|
+
"x-grok-client-version": GROK_CLI_VERSION,
|
|
63
|
+
"x-grok-client-identifier": GROK_CLI_CLIENT_IDENTIFIER,
|
|
64
|
+
"x-grok-client-mode": "headless",
|
|
65
|
+
};
|
|
66
|
+
const email = providerSpecificData?.email;
|
|
67
|
+
const userId = providerSpecificData?.userId || providerSpecificData?.principalId;
|
|
68
|
+
if (email) headers["x-email"] = email;
|
|
69
|
+
if (userId) headers["x-userid"] = userId;
|
|
70
|
+
return headers;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export async function resolveGrokCliModels(credentials, options = {}) {
|
|
74
|
+
const {
|
|
75
|
+
fetchFn = proxyAwareFetch,
|
|
76
|
+
log = console,
|
|
77
|
+
proxyOptions = null,
|
|
78
|
+
onCredentialsRefreshed,
|
|
79
|
+
} = options;
|
|
80
|
+
let accessToken = credentials?.accessToken;
|
|
81
|
+
if (!accessToken) return { models: [], warning: "Grok CLI access token is missing." };
|
|
82
|
+
|
|
83
|
+
const request = (token) => fetchFn(
|
|
84
|
+
MODELS_URL,
|
|
85
|
+
{
|
|
86
|
+
method: "GET",
|
|
87
|
+
headers: buildHeaders(token, credentials?.providerSpecificData),
|
|
88
|
+
},
|
|
89
|
+
proxyOptions,
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
let response = await request(accessToken);
|
|
94
|
+
if ((response.status === 401 || response.status === 403) && credentials?.refreshToken) {
|
|
95
|
+
const refreshed = await refreshProviderCredentials(
|
|
96
|
+
"grok-cli",
|
|
97
|
+
credentials,
|
|
98
|
+
log,
|
|
99
|
+
proxyOptions,
|
|
100
|
+
);
|
|
101
|
+
if (refreshed?.accessToken) {
|
|
102
|
+
accessToken = refreshed.accessToken;
|
|
103
|
+
try {
|
|
104
|
+
await onCredentialsRefreshed?.(refreshed);
|
|
105
|
+
} catch (error) {
|
|
106
|
+
log?.warn?.("Grok CLI credential persistence failed", error);
|
|
107
|
+
}
|
|
108
|
+
response = await request(accessToken);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (!response.ok) {
|
|
113
|
+
const detail = await response.text().catch(() => "");
|
|
114
|
+
return {
|
|
115
|
+
models: [],
|
|
116
|
+
warning: `Grok CLI model discovery failed (${response.status})${detail ? `: ${detail.slice(0, 160)}` : ""}`,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const models = parseGrokCliModels(await response.json());
|
|
121
|
+
return models.length
|
|
122
|
+
? { models }
|
|
123
|
+
: { models: [], warning: "Grok CLI returned no selectable models." };
|
|
124
|
+
} catch (error) {
|
|
125
|
+
return { models: [], warning: `Grok CLI model discovery failed: ${error.message}` };
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -17,6 +17,10 @@ for (const entry of REGISTRY) {
|
|
|
17
17
|
for (const a of entry.aliases || []) ALIAS_TO_PROVIDER_ID[a] = entry.id;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
const BUILTIN_MODEL_ALIASES = {
|
|
21
|
+
"grok-build": "gcli/grok-build",
|
|
22
|
+
};
|
|
23
|
+
|
|
20
24
|
/**
|
|
21
25
|
* Resolve provider alias to provider ID
|
|
22
26
|
*/
|
|
@@ -104,7 +108,9 @@ export async function getModelInfoCore(modelStr, aliasesOrGetter) {
|
|
|
104
108
|
: aliasesOrGetter;
|
|
105
109
|
|
|
106
110
|
// Resolve alias
|
|
107
|
-
const resolved =
|
|
111
|
+
const resolved =
|
|
112
|
+
resolveModelAliasFromMap(parsed.model, aliases) ||
|
|
113
|
+
resolveModelAliasFromMap(parsed.model, BUILTIN_MODEL_ALIASES);
|
|
108
114
|
if (resolved) {
|
|
109
115
|
return resolved;
|
|
110
116
|
}
|
|
@@ -105,7 +105,7 @@ export function detectFormat(body) {
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
// Get provider config (internal — no external runtime consumer)
|
|
108
|
-
|
|
108
|
+
function getProviderConfig(provider) {
|
|
109
109
|
if (isOpenAICompatible(provider)) {
|
|
110
110
|
const apiType = getOpenAICompatibleType(provider);
|
|
111
111
|
return {
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
findWorkingProxy,
|
|
3
3
|
clearProxyFallbackCache
|
|
4
4
|
} from "@omniroute/open-sse/utils/proxyFallback.ts";
|
|
5
|
-
import { isFeatureFlagEnabled } from '
|
|
5
|
+
import { isFeatureFlagEnabled } from '../../dist/shared/utils/featureFlags.js';
|
|
6
6
|
async function selectProxyForValidation(targetUrl) {
|
|
7
7
|
if (!isFeatureFlagEnabled("PROXY_AUTO_SELECT_ENABLED")) return null;
|
|
8
8
|
if (!targetUrl) return null;
|
|
@@ -2,7 +2,7 @@ import { PROVIDERS, PROVIDER_OAUTH } from "../../config/providers.js";
|
|
|
2
2
|
import { OAUTH_ENDPOINTS, GITHUB_COPILOT } from "../../config/appConstants.js";
|
|
3
3
|
import { proxyAwareFetch } from "../../utils/proxyFetch.js";
|
|
4
4
|
import { dedupRefresh } from "./dedup.js";
|
|
5
|
-
import { buildExternalIdpRefreshParams } from '
|
|
5
|
+
import { buildExternalIdpRefreshParams } from '../../../dist/lib/oauth/kiroExternalIdp.js';
|
|
6
6
|
|
|
7
7
|
let _xaiServiceSingleton = null;
|
|
8
8
|
export async function refreshXaiToken(refreshToken, log) {
|
|
@@ -10,7 +10,7 @@ export async function refreshXaiToken(refreshToken, log) {
|
|
|
10
10
|
return dedupRefresh("xai", refreshToken, async () => {
|
|
11
11
|
try {
|
|
12
12
|
if (!_xaiServiceSingleton) {
|
|
13
|
-
const mod = await import('
|
|
13
|
+
const mod = await import('../../../dist/lib/oauth/services/xai.js');
|
|
14
14
|
_xaiServiceSingleton = new mod.XaiService();
|
|
15
15
|
}
|
|
16
16
|
const tokens = await _xaiServiceSingleton.refreshAccessToken(refreshToken);
|
|
@@ -296,7 +296,7 @@ async function resolveKiroProfileArnPatch(providerSpecificData, accessToken, ref
|
|
|
296
296
|
if (providerSpecificData?.profileArn) return {};
|
|
297
297
|
let profileArn = refreshedArn?.trim?.() || null;
|
|
298
298
|
if (!profileArn) {
|
|
299
|
-
const { fetchKiroProfileArn } = await import('
|
|
299
|
+
const { fetchKiroProfileArn } = await import('../../../dist/lib/oauth/providers.js');
|
|
300
300
|
profileArn = await fetchKiroProfileArn(accessToken);
|
|
301
301
|
}
|
|
302
302
|
return profileArn ? { providerSpecificData: { profileArn } } : {};
|
|
@@ -1,267 +1,201 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Codex (OpenAI
|
|
3
|
-
* Updated from OmniRoute — supports dual-window quota, code_review, spark, bankedResetCredits
|
|
2
|
+
* Codex (OpenAI) usage handler
|
|
4
3
|
*/
|
|
5
4
|
|
|
6
5
|
import { proxyAwareFetch } from "../../utils/proxyFetch.js";
|
|
6
|
+
import { U, parseResetTime, toFiniteNumber } from "./shared.js";
|
|
7
7
|
|
|
8
|
-
// Codex (OpenAI) API config
|
|
8
|
+
// Codex (OpenAI) API config
|
|
9
9
|
const CODEX_CONFIG = {
|
|
10
|
-
usageUrl: "
|
|
10
|
+
usageUrl: U("codex").url,
|
|
11
|
+
resetCreditsUrl: U("codex").resetCreditsUrl,
|
|
12
|
+
resetCreditsConsumeUrl: U("codex").resetCreditsConsumeUrl,
|
|
11
13
|
};
|
|
12
14
|
|
|
13
|
-
function
|
|
14
|
-
if (!
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
function toRecord(value) {
|
|
22
|
-
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
15
|
+
function toIsoDate(value) {
|
|
16
|
+
if (!value) return null;
|
|
17
|
+
const date = value instanceof Date
|
|
18
|
+
? value
|
|
19
|
+
: new Date(typeof value === "number" && value < 1e12 ? value * 1000 : value);
|
|
20
|
+
const time = date.getTime();
|
|
21
|
+
return Number.isFinite(time) ? date.toISOString() : null;
|
|
23
22
|
}
|
|
24
23
|
|
|
25
|
-
function
|
|
26
|
-
|
|
27
|
-
if (typeof value === "string" && value.trim().length > 0) {
|
|
28
|
-
const parsed = Number(value);
|
|
29
|
-
return Number.isFinite(parsed) ? parsed : fallback;
|
|
30
|
-
}
|
|
31
|
-
return fallback;
|
|
24
|
+
function getCodexAccountId(providerSpecificData) {
|
|
25
|
+
return providerSpecificData?.workspaceId || providerSpecificData?.accountId || providerSpecificData?.chatgptAccountId || null;
|
|
32
26
|
}
|
|
33
27
|
|
|
34
|
-
function
|
|
35
|
-
if (!
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
date = resetValue;
|
|
40
|
-
} else if (typeof resetValue === "number") {
|
|
41
|
-
date = new Date(resetValue < 1e12 ? resetValue * 1000 : resetValue);
|
|
42
|
-
} else if (typeof resetValue === "string") {
|
|
43
|
-
if (/^\d+$/.test(resetValue)) {
|
|
44
|
-
const ts = Number(resetValue);
|
|
45
|
-
date = new Date(ts < 1e12 ? ts * 1000 : ts);
|
|
46
|
-
} else {
|
|
47
|
-
date = new Date(resetValue);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
if (!date || date.getTime() <= 0) return null;
|
|
51
|
-
return date.toISOString();
|
|
52
|
-
} catch {
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
28
|
+
function getCodexRateLimitBody(snapshot) {
|
|
29
|
+
if (!snapshot || typeof snapshot !== "object" || Array.isArray(snapshot)) return null;
|
|
30
|
+
return snapshot.rate_limit && typeof snapshot.rate_limit === "object"
|
|
31
|
+
? snapshot.rate_limit
|
|
32
|
+
: snapshot;
|
|
55
33
|
}
|
|
56
34
|
|
|
57
|
-
function
|
|
58
|
-
const
|
|
59
|
-
const resetAfterSeconds = toNumber(getFieldValue(window, "reset_after_seconds", "resetAfterSeconds"), 0);
|
|
60
|
-
if (resetAt > 0) return parseResetTime(resetAt * 1000);
|
|
61
|
-
if (resetAfterSeconds > 0) return parseResetTime(Date.now() + resetAfterSeconds * 1000);
|
|
62
|
-
return null;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function buildPercentageQuota(window, displayName) {
|
|
66
|
-
const usedPercent = toNumber(getFieldValue(window, "used_percent", "usedPercent"), 0);
|
|
35
|
+
function formatCodexWindow(window) {
|
|
36
|
+
const used = Math.max(0, Math.min(100, toFiniteNumber(window?.used_percent ?? window?.percent_used, 0)));
|
|
67
37
|
return {
|
|
68
|
-
used
|
|
38
|
+
used,
|
|
69
39
|
total: 100,
|
|
70
|
-
remaining: 100 -
|
|
71
|
-
resetAt:
|
|
40
|
+
remaining: Math.max(0, 100 - used),
|
|
41
|
+
resetAt: parseResetTime(window?.reset_at ?? window?.resets_at ?? window?.resetAt ?? null),
|
|
72
42
|
unlimited: false,
|
|
73
|
-
...(displayName ? { displayName } : {}),
|
|
74
43
|
};
|
|
75
44
|
}
|
|
76
45
|
|
|
77
|
-
function
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const normalized = value.trim().toLowerCase();
|
|
81
|
-
if (!normalized) return false;
|
|
82
|
-
return (
|
|
83
|
-
normalized === "code_review" ||
|
|
84
|
-
normalized === "codex_review" ||
|
|
85
|
-
normalized === "review" ||
|
|
86
|
-
normalized.includes("code_review") ||
|
|
87
|
-
normalized.includes("codex_review") ||
|
|
88
|
-
normalized.includes("code review")
|
|
89
|
-
);
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function findCodexReviewRateLimit(data) {
|
|
94
|
-
const additionalRateLimits = getFieldValue(data, "additional_rate_limits", "additionalRateLimits");
|
|
95
|
-
if (!Array.isArray(additionalRateLimits)) return {};
|
|
96
|
-
for (const entry of additionalRateLimits) {
|
|
97
|
-
const rec = toRecord(entry);
|
|
98
|
-
if (
|
|
99
|
-
isCodexReviewLimitDescriptor(
|
|
100
|
-
getFieldValue(rec, "limit_name", "limitName"),
|
|
101
|
-
getFieldValue(rec, "metered_feature", "meteredFeature"),
|
|
102
|
-
getFieldValue(rec, "limit_id", "limitId"),
|
|
103
|
-
rec["id"], rec["name"]
|
|
104
|
-
)
|
|
105
|
-
) {
|
|
106
|
-
return toRecord(getFieldValue(rec, "rate_limit", "rateLimit"));
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
return {};
|
|
110
|
-
}
|
|
46
|
+
function appendCodexQuotaWindows(quotas, prefix, snapshot) {
|
|
47
|
+
const rateLimit = getCodexRateLimitBody(snapshot);
|
|
48
|
+
if (!rateLimit) return false;
|
|
111
49
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const normalized = value.trim().toLowerCase();
|
|
116
|
-
return normalized === "spark" || normalized.includes("spark");
|
|
117
|
-
});
|
|
118
|
-
}
|
|
50
|
+
const primary = rateLimit.primary_window || rateLimit.primary || snapshot.primary_window || snapshot.primary;
|
|
51
|
+
const secondary = rateLimit.secondary_window || rateLimit.secondary || snapshot.secondary_window || snapshot.secondary;
|
|
52
|
+
let added = false;
|
|
119
53
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
getFieldValue(rec, "limit_name", "limitName"),
|
|
128
|
-
getFieldValue(rec, "metered_feature", "meteredFeature"),
|
|
129
|
-
getFieldValue(rec, "limit_id", "limitId"),
|
|
130
|
-
rec["id"], rec["name"], rec["model"],
|
|
131
|
-
getFieldValue(rec, "model_id", "modelId")
|
|
132
|
-
)
|
|
133
|
-
) {
|
|
134
|
-
return toRecord(getFieldValue(rec, "rate_limit", "rateLimit"));
|
|
135
|
-
}
|
|
54
|
+
if (primary) {
|
|
55
|
+
quotas[prefix ? `${prefix}_session` : "session"] = formatCodexWindow(primary);
|
|
56
|
+
added = true;
|
|
57
|
+
}
|
|
58
|
+
if (secondary) {
|
|
59
|
+
quotas[prefix ? `${prefix}_weekly` : "weekly"] = formatCodexWindow(secondary);
|
|
60
|
+
added = true;
|
|
136
61
|
}
|
|
137
|
-
return {};
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
function parseBankedResetCredits(data) {
|
|
141
|
-
const resetCredits = toRecord(getFieldValue(data, "rate_limit_reset_credits", "rateLimitResetCredits"));
|
|
142
|
-
const availableCount = getFieldValue(resetCredits, "available_count", "availableCount");
|
|
143
|
-
const count = toNumber(availableCount, NaN);
|
|
144
|
-
return Number.isFinite(count) ? count : undefined;
|
|
145
|
-
}
|
|
146
62
|
|
|
147
|
-
|
|
148
|
-
const reachedType = getFieldValue(data, "rate_limit_reached_type", "rateLimitReachedType");
|
|
149
|
-
if (typeof reachedType === "string" && reachedType.trim().length > 0) return reachedType.trim();
|
|
150
|
-
const reachedTypeObj = toRecord(reachedType);
|
|
151
|
-
const type = getFieldValue(reachedTypeObj, "type");
|
|
152
|
-
return typeof type === "string" && type.trim().length > 0 ? type.trim() : undefined;
|
|
63
|
+
return added;
|
|
153
64
|
}
|
|
154
65
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
*/
|
|
159
|
-
function buildCodexUsageQuotas(dataValue) {
|
|
160
|
-
const data = toRecord(dataValue);
|
|
161
|
-
const rateLimit = toRecord(getFieldValue(data, "rate_limit", "rateLimit"));
|
|
162
|
-
const quotas = {};
|
|
163
|
-
const bankedResetCredits = parseBankedResetCredits(data);
|
|
164
|
-
const rateLimitReachedType = parseRateLimitReachedType(data);
|
|
165
|
-
|
|
166
|
-
// Primary window (5h session)
|
|
167
|
-
const primaryWindow = toRecord(getFieldValue(rateLimit, "primary_window", "primaryWindow"));
|
|
168
|
-
if (Object.keys(primaryWindow).length > 0) quotas.session = buildPercentageQuota(primaryWindow);
|
|
169
|
-
|
|
170
|
-
// Secondary window (7d weekly)
|
|
171
|
-
const secondaryWindow = toRecord(getFieldValue(rateLimit, "secondary_window", "secondaryWindow"));
|
|
172
|
-
if (Object.keys(secondaryWindow).length > 0) quotas.weekly = buildPercentageQuota(secondaryWindow);
|
|
173
|
-
|
|
174
|
-
// Code review rate limit (dedicated block or additional_rate_limits fallback)
|
|
175
|
-
const dedicatedReviewRateLimit = toRecord(getFieldValue(data, "code_review_rate_limit", "codeReviewRateLimit"));
|
|
176
|
-
const reviewRateLimit = Object.keys(dedicatedReviewRateLimit).length > 0
|
|
177
|
-
? dedicatedReviewRateLimit
|
|
178
|
-
: findCodexReviewRateLimit(data);
|
|
179
|
-
|
|
180
|
-
const codeReviewWindow = toRecord(getFieldValue(reviewRateLimit, "primary_window", "primaryWindow"));
|
|
181
|
-
if (getFieldValue(codeReviewWindow, "used_percent", "usedPercent") !== null ||
|
|
182
|
-
getFieldValue(codeReviewWindow, "remaining_count", "remainingCount") !== null) {
|
|
183
|
-
quotas.code_review = buildPercentageQuota(codeReviewWindow);
|
|
66
|
+
function getCodexReviewRateLimit(data) {
|
|
67
|
+
if (data.code_review_rate_limit || data.review_rate_limit) {
|
|
68
|
+
return data.code_review_rate_limit || data.review_rate_limit;
|
|
184
69
|
}
|
|
185
70
|
|
|
186
|
-
const
|
|
187
|
-
if (
|
|
188
|
-
|
|
189
|
-
quotas.code_review_weekly = buildPercentageQuota(codeReviewSecondaryWindow);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
// Spark quota (additional_rate_limits)
|
|
193
|
-
const sparkRateLimit = findCodexSparkRateLimit(data);
|
|
194
|
-
const sparkPrimaryWindow = toRecord(getFieldValue(sparkRateLimit, "primary_window", "primaryWindow"));
|
|
195
|
-
if (Object.keys(sparkPrimaryWindow).length > 0) {
|
|
196
|
-
quotas.spark = buildPercentageQuota(sparkPrimaryWindow, "Spark");
|
|
197
|
-
}
|
|
198
|
-
const sparkSecondaryWindow = toRecord(getFieldValue(sparkRateLimit, "secondary_window", "secondaryWindow"));
|
|
199
|
-
if (Object.keys(sparkSecondaryWindow).length > 0) {
|
|
200
|
-
quotas.spark_weekly = buildPercentageQuota(sparkSecondaryWindow, "Spark Weekly");
|
|
71
|
+
const byLimitId = data.rate_limits_by_limit_id;
|
|
72
|
+
if (byLimitId && typeof byLimitId === "object" && !Array.isArray(byLimitId)) {
|
|
73
|
+
return byLimitId.code_review || byLimitId.codex_review || byLimitId.review || null;
|
|
201
74
|
}
|
|
202
75
|
|
|
203
|
-
|
|
76
|
+
const additional = Array.isArray(data.additional_rate_limits) ? data.additional_rate_limits : [];
|
|
77
|
+
return additional.find((entry) => {
|
|
78
|
+
const id = String(entry?.limit_name || entry?.metered_feature || entry?.id || "").toLowerCase();
|
|
79
|
+
return id === "code_review" || id === "codex_review" || id === "review" || id.includes("review");
|
|
80
|
+
}) || null;
|
|
204
81
|
}
|
|
205
82
|
|
|
206
|
-
|
|
207
|
-
* Codex (OpenAI) Usage - Fetch from ChatGPT /wham/usage API
|
|
208
|
-
* Uses persisted workspaceId from OAuth for correct workspace binding.
|
|
209
|
-
*/
|
|
210
|
-
export async function getCodexUsage(accessToken, providerSpecificData = {}) {
|
|
83
|
+
export async function getCodexUsage(accessToken, proxyOptions = null) {
|
|
211
84
|
try {
|
|
212
|
-
const accountId = typeof providerSpecificData?.workspaceId === "string"
|
|
213
|
-
? providerSpecificData.workspaceId
|
|
214
|
-
: null;
|
|
215
|
-
|
|
216
|
-
const headers = {
|
|
217
|
-
Authorization: `Bearer ${accessToken}`,
|
|
218
|
-
"Content-Type": "application/json",
|
|
219
|
-
Accept: "application/json",
|
|
220
|
-
};
|
|
221
|
-
if (accountId) {
|
|
222
|
-
headers["chatgpt-account-id"] = accountId;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
85
|
const response = await proxyAwareFetch(CODEX_CONFIG.usageUrl, {
|
|
226
86
|
method: "GET",
|
|
227
|
-
headers
|
|
228
|
-
|
|
87
|
+
headers: {
|
|
88
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
89
|
+
"Accept": "application/json",
|
|
90
|
+
},
|
|
91
|
+
}, proxyOptions);
|
|
229
92
|
|
|
230
93
|
if (!response.ok) {
|
|
231
|
-
|
|
232
|
-
return {
|
|
233
|
-
message: "Codex token expired or access denied. Please re-authenticate the connection.",
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
|
-
throw new Error(`Codex API error: ${response.status}`);
|
|
94
|
+
return { message: `Codex connected. Usage API temporarily unavailable (${response.status}).` };
|
|
237
95
|
}
|
|
238
96
|
|
|
239
97
|
const data = await response.json();
|
|
240
|
-
const
|
|
98
|
+
const normalRateLimit = data.rate_limit || data.rate_limits || data.rate_limits_by_limit_id?.codex || {};
|
|
99
|
+
const reviewRateLimit = getCodexReviewRateLimit(data);
|
|
100
|
+
const availableResetCredits = Math.max(0, toFiniteNumber(data.rate_limit_reset_credits?.available_count, 0));
|
|
101
|
+
const quotas = {};
|
|
102
|
+
|
|
103
|
+
appendCodexQuotaWindows(quotas, "", normalRateLimit);
|
|
104
|
+
appendCodexQuotaWindows(quotas, "review", reviewRateLimit);
|
|
241
105
|
|
|
242
106
|
return {
|
|
243
|
-
plan:
|
|
244
|
-
limitReached:
|
|
107
|
+
plan: data.plan_type || data.summary?.plan || "unknown",
|
|
108
|
+
limitReached: getCodexRateLimitBody(normalRateLimit)?.limit_reached || false,
|
|
109
|
+
reviewLimitReached: getCodexRateLimitBody(reviewRateLimit)?.limit_reached || false,
|
|
110
|
+
resetCredits: { availableCount: availableResetCredits },
|
|
245
111
|
quotas,
|
|
246
|
-
...(bankedResetCredits !== undefined ? { bankedResetCredits } : {}),
|
|
247
|
-
...(rateLimitReachedType !== undefined ? { rateLimitReachedType } : {}),
|
|
248
112
|
};
|
|
249
113
|
} catch (error) {
|
|
250
|
-
|
|
114
|
+
throw new Error(`Failed to fetch Codex usage: ${error.message}`);
|
|
251
115
|
}
|
|
252
116
|
}
|
|
253
117
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
}
|
|
118
|
+
export async function getCodexRateLimitResetCredits(accessToken, proxyOptions = null, providerSpecificData = null) {
|
|
119
|
+
if (!accessToken) {
|
|
120
|
+
throw new Error("No Codex access token available. Please re-authorize the connection.");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const accountId = getCodexAccountId(providerSpecificData);
|
|
124
|
+
const headers = {
|
|
125
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
126
|
+
"Accept": "application/json",
|
|
127
|
+
"OpenAI-Beta": "codex-1",
|
|
128
|
+
"originator": "codex_cli_rs",
|
|
129
|
+
};
|
|
130
|
+
if (accountId) headers["ChatGPT-Account-ID"] = accountId;
|
|
131
|
+
|
|
132
|
+
const response = await proxyAwareFetch(CODEX_CONFIG.resetCreditsUrl, {
|
|
133
|
+
method: "GET",
|
|
134
|
+
headers,
|
|
135
|
+
}, proxyOptions);
|
|
258
136
|
|
|
259
|
-
|
|
260
|
-
export async function getCodexRateLimitResetCredits(accessToken, providerSpecificData = {}) {
|
|
137
|
+
let data = null;
|
|
261
138
|
try {
|
|
262
|
-
|
|
263
|
-
return { credits: result.bankedResetCredits || 0 };
|
|
139
|
+
data = await response.json();
|
|
264
140
|
} catch {
|
|
265
|
-
|
|
141
|
+
data = null;
|
|
266
142
|
}
|
|
143
|
+
|
|
144
|
+
if (!response.ok) {
|
|
145
|
+
const message = data?.message || data?.error || data?.detail || `Codex reset credits API unavailable (${response.status}).`;
|
|
146
|
+
throw new Error(message);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const credits = Array.isArray(data?.credits) ? data.credits : [];
|
|
150
|
+
return {
|
|
151
|
+
availableCount: Math.max(0, toFiniteNumber(data?.available_count ?? data?.availableCount, 0)),
|
|
152
|
+
credits: credits.map((credit) => ({
|
|
153
|
+
status: String(credit?.status || "unknown"),
|
|
154
|
+
grantedAt: toIsoDate(credit?.granted_at ?? credit?.grantedAt),
|
|
155
|
+
expiresAt: toIsoDate(credit?.expires_at ?? credit?.expiresAt),
|
|
156
|
+
})),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Consume one Codex rate-limit reset credit (irreversible, spends 1 credit)
|
|
161
|
+
export async function consumeCodexRateLimitResetCredit(accessToken, redeemRequestId, proxyOptions = null) {
|
|
162
|
+
if (!accessToken) {
|
|
163
|
+
throw new Error("No Codex access token available. Please re-authorize the connection.");
|
|
164
|
+
}
|
|
165
|
+
if (!redeemRequestId || typeof redeemRequestId !== "string") {
|
|
166
|
+
throw new Error("A redeem request id is required to consume a Codex reset credit.");
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
let response;
|
|
170
|
+
let data = null;
|
|
171
|
+
try {
|
|
172
|
+
response = await proxyAwareFetch(CODEX_CONFIG.resetCreditsConsumeUrl, {
|
|
173
|
+
method: "POST",
|
|
174
|
+
headers: {
|
|
175
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
176
|
+
"Accept": "application/json",
|
|
177
|
+
"Content-Type": "application/json",
|
|
178
|
+
},
|
|
179
|
+
body: JSON.stringify({ redeem_request_id: redeemRequestId }),
|
|
180
|
+
}, proxyOptions);
|
|
181
|
+
|
|
182
|
+
const text = await response.text();
|
|
183
|
+
data = text ? JSON.parse(text) : null;
|
|
184
|
+
} catch (error) {
|
|
185
|
+
throw new Error(`Failed to consume Codex reset credit: ${error.message}`);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const code = data?.code || null;
|
|
189
|
+
const windowsReset = toFiniteNumber(data?.windows_reset, 0);
|
|
190
|
+
const success = response.ok && (code === "reset" || windowsReset > 0);
|
|
191
|
+
|
|
192
|
+
return {
|
|
193
|
+
ok: success,
|
|
194
|
+
noCredit: response.ok && code === "no_credit",
|
|
195
|
+
status: response.status,
|
|
196
|
+
code,
|
|
197
|
+
windowsReset,
|
|
198
|
+
message: data?.message || null,
|
|
199
|
+
raw: data,
|
|
200
|
+
};
|
|
267
201
|
}
|