@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
|
@@ -1,119 +1,552 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import { BaseExecutor } from "./base.js";
|
|
3
|
+
import { PROVIDERS } from "../config/providers.js";
|
|
4
|
+
import {
|
|
5
|
+
refreshProviderCredentials,
|
|
6
|
+
shouldRefreshCredentials,
|
|
7
|
+
} from "../services/oauthCredentialManager.js";
|
|
8
|
+
import { normalizeResponsesInput } from "../translator/formats/responsesApi.js";
|
|
9
|
+
import { getModelUpstreamId } from "../config/providerModels.js";
|
|
10
|
+
import {
|
|
11
|
+
GROK_CLI_CLIENT_IDENTIFIER,
|
|
12
|
+
GROK_CLI_VERSION,
|
|
13
|
+
supportsGrokCliReasoningEffort,
|
|
14
|
+
} from "../config/grokCli.js";
|
|
15
|
+
import { MEMORY_CONFIG } from "../config/runtimeConfig.js";
|
|
16
|
+
import { resolveSessionId } from "../utils/sessionManager.js";
|
|
17
|
+
import { getConsistentMachineId } from "../shared/machineId.js";
|
|
18
|
+
|
|
19
|
+
// Server-generated item id prefixes that /responses cannot resolve when store=false
|
|
20
|
+
const SERVER_ID_PATTERN = /^(rs|fc|resp|msg)_/;
|
|
21
|
+
|
|
22
|
+
// Hosted tool types executed server-side by Grok CLI backend
|
|
23
|
+
const HOSTED_TOOL_TYPES = new Set([
|
|
24
|
+
"web_search",
|
|
25
|
+
"x_search",
|
|
26
|
+
"web_search_preview",
|
|
27
|
+
"file_search",
|
|
28
|
+
"image_generation",
|
|
29
|
+
"code_interpreter",
|
|
30
|
+
"mcp",
|
|
31
|
+
"local_shell",
|
|
32
|
+
]);
|
|
33
|
+
|
|
34
|
+
// Fields accepted by cli-chat-proxy Responses API (mirrors Codex allowlist + Grok extras)
|
|
35
|
+
const RESPONSES_API_ALLOWLIST = new Set([
|
|
36
|
+
"model",
|
|
37
|
+
"input",
|
|
38
|
+
"instructions",
|
|
39
|
+
"tools",
|
|
40
|
+
"tool_choice",
|
|
41
|
+
"stream",
|
|
42
|
+
"store",
|
|
43
|
+
"reasoning",
|
|
44
|
+
"include",
|
|
45
|
+
"temperature",
|
|
46
|
+
"top_p",
|
|
47
|
+
"max_output_tokens",
|
|
48
|
+
"parallel_tool_calls",
|
|
49
|
+
"text",
|
|
50
|
+
"metadata",
|
|
51
|
+
"prompt_cache_key",
|
|
52
|
+
]);
|
|
53
|
+
|
|
54
|
+
const EFFORT_LEVELS = ["low", "medium", "high", "xhigh"];
|
|
55
|
+
const GROK_CLI_TURN_STORE_MAX = 5000;
|
|
56
|
+
const GROK_CLI_NATIVE_ITEM_ID = /^(?:rs|msg|fc)_[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
57
|
+
const GROK_CLI_FREEFORM_TOOL_PARAMETERS = {
|
|
58
|
+
type: "object",
|
|
59
|
+
properties: { input: { type: "string" } },
|
|
60
|
+
required: ["input"],
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// Per-session last turn index so multi-turn headers never go backwards within this process
|
|
64
|
+
const sessionTurnStore = new Map();
|
|
65
|
+
let requestTurnStore = new WeakMap();
|
|
66
|
+
|
|
1
67
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* NOTE: Requires xAI credits or Grok subscription.
|
|
7
|
-
* Free Grok 4.5 is only available via the Grok CLI TUI, not via API.
|
|
68
|
+
* Count user turns in a Responses `input` array.
|
|
69
|
+
* Official CLI sets x-grok-turn-idx to the 1-based conversation turn (≈ user messages).
|
|
70
|
+
* HAR: first chat turn → "1".
|
|
8
71
|
*/
|
|
72
|
+
export function countGrokCliUserTurns(input) {
|
|
73
|
+
if (!Array.isArray(input)) return 1;
|
|
74
|
+
let n = 0;
|
|
75
|
+
for (const item of input) {
|
|
76
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) continue;
|
|
77
|
+
const type = typeof item.type === "string" ? item.type : "";
|
|
78
|
+
// Responses message items (type omitted or "message") with role user
|
|
79
|
+
if (item.role === "user" && (!type || type === "message")) n += 1;
|
|
80
|
+
}
|
|
81
|
+
return Math.max(1, n);
|
|
82
|
+
}
|
|
9
83
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
84
|
+
/**
|
|
85
|
+
* Resolve monotonic turn index for a session.
|
|
86
|
+
* Prefers user-message count from the payload (full history clients), but never
|
|
87
|
+
* decreases vs the last index observed for the same sessionId in this process.
|
|
88
|
+
*/
|
|
89
|
+
export function resolveGrokCliTurnIdx(sessionId, input, requestKey = null) {
|
|
90
|
+
const fromInput = countGrokCliUserTurns(input);
|
|
91
|
+
if (!sessionId) return fromInput;
|
|
92
|
+
|
|
93
|
+
if (requestKey && requestTurnStore.has(requestKey)) {
|
|
94
|
+
return requestTurnStore.get(requestKey);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const now = Date.now();
|
|
98
|
+
const existing = sessionTurnStore.get(sessionId);
|
|
99
|
+
const prev = existing && now - existing.lastUsed <= MEMORY_CONFIG.sessionTtlMs
|
|
100
|
+
? existing.turn
|
|
101
|
+
: 0;
|
|
102
|
+
if (existing) sessionTurnStore.delete(sessionId);
|
|
103
|
+
|
|
104
|
+
// A new delta-style request advances the turn; retries reuse requestKey.
|
|
105
|
+
const turn = prev > 0 ? Math.max(fromInput, prev + (requestKey ? 1 : 0)) : fromInput;
|
|
106
|
+
while (sessionTurnStore.size >= GROK_CLI_TURN_STORE_MAX) {
|
|
107
|
+
sessionTurnStore.delete(sessionTurnStore.keys().next().value);
|
|
108
|
+
}
|
|
109
|
+
sessionTurnStore.set(sessionId, { turn, lastUsed: now });
|
|
110
|
+
if (requestKey) requestTurnStore.set(requestKey, turn);
|
|
111
|
+
return turn;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Test helper — clear in-memory turn counters */
|
|
115
|
+
export function _resetGrokCliTurnStore() {
|
|
116
|
+
sessionTurnStore.clear();
|
|
117
|
+
requestTurnStore = new WeakMap();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function _getGrokCliTurnStoreSize() {
|
|
121
|
+
return sessionTurnStore.size;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function normalizeGrokCliEffort(value) {
|
|
125
|
+
const effort = typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
126
|
+
if (effort === "max") return "xhigh";
|
|
127
|
+
if (EFFORT_LEVELS.includes(effort)) return effort;
|
|
128
|
+
return "high";
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export { supportsGrokCliReasoningEffort } from "../config/grokCli.js";
|
|
132
|
+
|
|
133
|
+
export function resolveGrokCliSessionId(credentials, body) {
|
|
134
|
+
// ponytail: clients without stable thread metadata share one connection session;
|
|
135
|
+
// split further when their wire format exposes a durable conversation id.
|
|
136
|
+
const explicitSessionBody = {
|
|
137
|
+
prompt_cache_key: body?.prompt_cache_key,
|
|
138
|
+
session_id: body?.session_id,
|
|
139
|
+
conversation_id: body?.conversation_id,
|
|
140
|
+
metadata: body?.metadata,
|
|
141
|
+
};
|
|
142
|
+
return resolveSessionId({
|
|
143
|
+
headers: credentials?.rawHeaders,
|
|
144
|
+
body: explicitSessionBody,
|
|
145
|
+
connectionId: credentials?.connectionId || credentials?.id,
|
|
146
|
+
workspaceId: credentials?.providerSpecificData?.workspaceId,
|
|
147
|
+
scope: "grok-cli",
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function stringifyGrokCliToolOutput(output) {
|
|
152
|
+
if (typeof output === "string") return output;
|
|
153
|
+
if (output === undefined) return "";
|
|
154
|
+
return JSON.stringify(output);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function isNativeGrokCliItemId(id) {
|
|
158
|
+
return typeof id === "string" && GROK_CLI_NATIVE_ITEM_ID.test(id);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function normalizeGrokCliInputItem(item) {
|
|
162
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) return item;
|
|
163
|
+
const { internal_chat_message_metadata_passthrough: _metadata, ...clean } = item;
|
|
164
|
+
|
|
165
|
+
if (item.type === "reasoning") {
|
|
166
|
+
if (!isNativeGrokCliItemId(item.id) || typeof item.encrypted_content !== "string") return null;
|
|
167
|
+
return clean;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (item.type === "custom_tool_call") {
|
|
171
|
+
const callId = item.call_id || item.id;
|
|
172
|
+
const name = typeof item.name === "string" ? item.name.trim() : "";
|
|
173
|
+
if (!callId || !name) return null;
|
|
174
|
+
return {
|
|
175
|
+
type: "function_call",
|
|
176
|
+
call_id: callId,
|
|
177
|
+
name,
|
|
178
|
+
arguments: JSON.stringify({ input: stringifyGrokCliToolOutput(item.input ?? item.arguments) }),
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (item.type === "custom_tool_call_output" || item.type === "function_call_output") {
|
|
183
|
+
const callId = item.call_id || item.id;
|
|
184
|
+
if (!callId) return null;
|
|
185
|
+
return {
|
|
186
|
+
type: "function_call_output",
|
|
187
|
+
call_id: callId,
|
|
188
|
+
output: stringifyGrokCliToolOutput(item.output),
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (item.type === "function_call") {
|
|
193
|
+
const callId = item.call_id || item.id;
|
|
194
|
+
const name = typeof item.name === "string" ? item.name.trim() : "";
|
|
195
|
+
if (!callId || !name) return null;
|
|
196
|
+
return {
|
|
197
|
+
type: "function_call",
|
|
198
|
+
...(isNativeGrokCliItemId(item.id) ? { id: item.id } : {}),
|
|
199
|
+
call_id: callId,
|
|
200
|
+
name,
|
|
201
|
+
arguments: typeof item.arguments === "string" ? item.arguments : JSON.stringify(item.arguments ?? {}),
|
|
202
|
+
...(typeof item.status === "string" ? { status: item.status } : {}),
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return clean;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export function normalizeGrokCliInput(body) {
|
|
210
|
+
if (!Array.isArray(body?.input)) return body;
|
|
211
|
+
const normalized = body.input.map(normalizeGrokCliInputItem).filter(Boolean);
|
|
212
|
+
const callIds = new Set(
|
|
213
|
+
normalized
|
|
214
|
+
.filter((item) => item?.type === "function_call" && item.call_id)
|
|
215
|
+
.map((item) => item.call_id)
|
|
216
|
+
);
|
|
217
|
+
body.input = normalized.filter(
|
|
218
|
+
(item) => item?.type !== "function_call_output" || callIds.has(item.call_id)
|
|
219
|
+
);
|
|
220
|
+
return body;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function stripStoredItemReferences(body) {
|
|
224
|
+
if (!Array.isArray(body.input)) return;
|
|
225
|
+
body.input = body.input.filter((item) => {
|
|
226
|
+
if (typeof item === "string" && SERVER_ID_PATTERN.test(item)) return false;
|
|
227
|
+
if (item && typeof item === "object" && !Array.isArray(item)) {
|
|
228
|
+
if (item.type === "item_reference") return false;
|
|
229
|
+
if (
|
|
230
|
+
typeof item.id === "string" &&
|
|
231
|
+
SERVER_ID_PATTERN.test(item.id) &&
|
|
232
|
+
!isNativeGrokCliItemId(item.id)
|
|
233
|
+
) delete item.id;
|
|
234
|
+
}
|
|
235
|
+
return true;
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Flatten Chat Completions tool shape → Responses flat format.
|
|
241
|
+
* Keep hosted tools (web_search / x_search) passthrough.
|
|
242
|
+
*/
|
|
243
|
+
function normalizeGrokCliTools(body) {
|
|
244
|
+
if (!Array.isArray(body.tools) || body.tools.length === 0) {
|
|
245
|
+
delete body.tools;
|
|
246
|
+
delete body.tool_choice;
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
const validNames = new Set();
|
|
250
|
+
const hostedTypes = new Set();
|
|
251
|
+
body.tools = body.tools.filter((tool) => {
|
|
252
|
+
if (!tool || typeof tool !== "object" || Array.isArray(tool)) return false;
|
|
253
|
+
const type = typeof tool.type === "string" ? tool.type : "";
|
|
254
|
+
|
|
255
|
+
if (type !== "function") {
|
|
256
|
+
// Hosted tools: { type: "web_search" } / { type: "x_search" }
|
|
257
|
+
if (HOSTED_TOOL_TYPES.has(type)) {
|
|
258
|
+
hostedTypes.add(type);
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
261
|
+
// Nested function shape without type
|
|
262
|
+
if (!type && tool.function) {
|
|
263
|
+
// fall through to function flatten below
|
|
264
|
+
} else if (!type || typeof tool.name === "string") {
|
|
265
|
+
// treat as bare function if name present
|
|
266
|
+
} else {
|
|
267
|
+
return false;
|
|
26
268
|
}
|
|
27
269
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
270
|
+
|
|
271
|
+
const isFunction =
|
|
272
|
+
type === "function" || type === "" || tool.function || typeof tool.name === "string";
|
|
273
|
+
if (!isFunction || HOSTED_TOOL_TYPES.has(type)) {
|
|
274
|
+
return HOSTED_TOOL_TYPES.has(type);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const fn =
|
|
278
|
+
tool.function && typeof tool.function === "object" && !Array.isArray(tool.function)
|
|
279
|
+
? tool.function
|
|
280
|
+
: null;
|
|
281
|
+
const rawName =
|
|
282
|
+
typeof tool.name === "string" ? tool.name : typeof fn?.name === "string" ? fn.name : "";
|
|
283
|
+
const name = rawName.trim();
|
|
284
|
+
if (!name) return false;
|
|
285
|
+
|
|
286
|
+
const description =
|
|
287
|
+
typeof tool.description === "string"
|
|
288
|
+
? tool.description
|
|
289
|
+
: typeof fn?.description === "string"
|
|
290
|
+
? fn.description
|
|
291
|
+
: "";
|
|
292
|
+
const parameters = type === "custom"
|
|
293
|
+
? GROK_CLI_FREEFORM_TOOL_PARAMETERS
|
|
294
|
+
: tool.parameters && typeof tool.parameters === "object" && !Array.isArray(tool.parameters)
|
|
295
|
+
? tool.parameters
|
|
296
|
+
: fn?.parameters && typeof fn.parameters === "object" && !Array.isArray(fn.parameters)
|
|
297
|
+
? fn.parameters
|
|
298
|
+
: { type: "object", properties: {} };
|
|
299
|
+
|
|
300
|
+
for (const k of Object.keys(tool)) delete tool[k];
|
|
301
|
+
tool.type = "function";
|
|
302
|
+
tool.name = name.slice(0, 128);
|
|
303
|
+
if (description) tool.description = description;
|
|
304
|
+
tool.parameters = parameters;
|
|
305
|
+
validNames.add(tool.name);
|
|
306
|
+
return true;
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
if (body.tools.length === 0) {
|
|
310
|
+
delete body.tools;
|
|
311
|
+
delete body.tool_choice;
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (body.tool_choice && typeof body.tool_choice === "object" && !Array.isArray(body.tool_choice)) {
|
|
316
|
+
const choiceType = typeof body.tool_choice.type === "string" ? body.tool_choice.type : "";
|
|
317
|
+
if (choiceType === "function" || choiceType === "custom") {
|
|
318
|
+
const rawName = body.tool_choice.name ?? body.tool_choice.function?.name;
|
|
319
|
+
const name = typeof rawName === "string" ? rawName.trim().slice(0, 128) : "";
|
|
320
|
+
if (!name || !validNames.has(name)) delete body.tool_choice;
|
|
321
|
+
else body.tool_choice = { type: "function", name };
|
|
322
|
+
} else if (!hostedTypes.has(choiceType)) {
|
|
323
|
+
delete body.tool_choice;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function resolveEffortFromModel(modelId) {
|
|
329
|
+
if (!modelId || typeof modelId !== "string") return null;
|
|
330
|
+
for (const level of EFFORT_LEVELS) {
|
|
331
|
+
if (modelId.endsWith(`-${level}`)) return level;
|
|
31
332
|
}
|
|
333
|
+
return null;
|
|
32
334
|
}
|
|
33
335
|
|
|
336
|
+
/**
|
|
337
|
+
* Grok CLI Executor — OpenAI Responses API on cli-chat-proxy.grok.com
|
|
338
|
+
* Auth: OAuth device-code access token (xai-grok-cli).
|
|
339
|
+
*/
|
|
34
340
|
export class GrokCliExecutor extends BaseExecutor {
|
|
35
341
|
constructor() {
|
|
36
342
|
super("grok-cli", PROVIDERS["grok-cli"]);
|
|
343
|
+
this._currentSessionId = null;
|
|
344
|
+
this._currentReqId = null;
|
|
345
|
+
this._currentTurnIdx = 1;
|
|
346
|
+
this._agentId = null;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
buildUrl() {
|
|
350
|
+
return this.config.baseUrl;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
async refreshCredentials(credentials, log, proxyOptions = null) {
|
|
354
|
+
if (!credentials?.refreshToken) return null;
|
|
355
|
+
return refreshProviderCredentials("grok-cli", credentials, log, proxyOptions);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
needsRefresh(credentials) {
|
|
359
|
+
return shouldRefreshCredentials("grok-cli", credentials);
|
|
37
360
|
}
|
|
38
361
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
362
|
+
buildHeaders(credentials, stream = true) {
|
|
363
|
+
const headers = super.buildHeaders(credentials, stream);
|
|
364
|
+
|
|
365
|
+
// Static fingerprint from registry
|
|
366
|
+
const staticHeaders = this.config.headers || {};
|
|
367
|
+
for (const [k, v] of Object.entries(staticHeaders)) {
|
|
368
|
+
if (v != null && headers[k] === undefined) headers[k] = v;
|
|
43
369
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
370
|
+
|
|
371
|
+
headers["x-grok-client-identifier"] =
|
|
372
|
+
this.config.clientIdentifier || headers["x-grok-client-identifier"] || GROK_CLI_CLIENT_IDENTIFIER;
|
|
373
|
+
headers["x-grok-client-version"] =
|
|
374
|
+
this.config.clientVersion || headers["x-grok-client-version"] || GROK_CLI_VERSION;
|
|
375
|
+
|
|
376
|
+
const sessionId = this._currentSessionId || credentials?.connectionId || crypto.randomUUID();
|
|
377
|
+
const reqId = this._currentReqId || crypto.randomUUID();
|
|
378
|
+
headers["x-grok-session-id"] = sessionId;
|
|
379
|
+
// CLI uses the same id for conv + session on chat turns
|
|
380
|
+
headers["x-grok-conv-id"] = sessionId;
|
|
381
|
+
headers["x-grok-req-id"] = reqId;
|
|
382
|
+
headers["x-grok-turn-idx"] = String(this._currentTurnIdx || 1);
|
|
383
|
+
|
|
384
|
+
if (this._agentId) headers["x-grok-agent-id"] = this._agentId;
|
|
385
|
+
|
|
386
|
+
// Surface model override (CLI always sets this)
|
|
387
|
+
if (this._currentModel) headers["x-grok-model-override"] = this._currentModel;
|
|
388
|
+
|
|
389
|
+
// Identity: mapTokens stores email top-level AND in providerSpecificData;
|
|
390
|
+
// fall back either way so OAuth connections always fingerprint like the CLI.
|
|
391
|
+
const psd = credentials?.providerSpecificData || {};
|
|
392
|
+
const email = psd.email || credentials?.email;
|
|
393
|
+
const userId = psd.userId || credentials?.userId || credentials?.providerUserId;
|
|
394
|
+
if (email) headers["x-email"] = email;
|
|
395
|
+
if (userId) headers["x-userid"] = userId;
|
|
396
|
+
|
|
397
|
+
return headers;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
parseError(response, bodyText) {
|
|
401
|
+
// 402 personal-team-blocked:spending-limit → surface as payment/quota for fallback
|
|
402
|
+
if (response.status === 402 && bodyText) {
|
|
403
|
+
try {
|
|
404
|
+
const json = JSON.parse(bodyText);
|
|
405
|
+
const code = json?.code || "";
|
|
406
|
+
const msg = json?.error || json?.message || bodyText;
|
|
407
|
+
return {
|
|
408
|
+
status: 402,
|
|
409
|
+
message: typeof msg === "string" ? msg : bodyText,
|
|
410
|
+
code: typeof code === "string" ? code : undefined,
|
|
411
|
+
};
|
|
412
|
+
} catch {
|
|
413
|
+
/* fall through */
|
|
414
|
+
}
|
|
56
415
|
}
|
|
416
|
+
return super.parseError(response, bodyText);
|
|
417
|
+
}
|
|
57
418
|
|
|
58
|
-
|
|
419
|
+
transformRequest(model, body, stream, credentials) {
|
|
420
|
+
// Session / request ids for headers — stable per client conversation when possible
|
|
421
|
+
const requestKey = body;
|
|
422
|
+
this._currentSessionId = resolveGrokCliSessionId(credentials, body);
|
|
423
|
+
this._currentReqId = crypto.randomUUID();
|
|
424
|
+
this._agentId =
|
|
425
|
+
credentials?.providerSpecificData?.deviceId ||
|
|
426
|
+
credentials?.providerSpecificData?.agentId ||
|
|
427
|
+
null;
|
|
59
428
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
};
|
|
429
|
+
// Normalize Responses input
|
|
430
|
+
const normalized = normalizeResponsesInput(body.input);
|
|
431
|
+
if (normalized) body.input = normalized;
|
|
64
432
|
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
433
|
+
// Chat Completions clients arrive with messages[] — translator should have
|
|
434
|
+
// converted already, but guard empty input.
|
|
435
|
+
if (!body.input || (Array.isArray(body.input) && body.input.length === 0)) {
|
|
436
|
+
if (Array.isArray(body.messages) && body.messages.length > 0) {
|
|
437
|
+
// Soft fallback: map messages → input messages (string content only)
|
|
438
|
+
body.input = body.messages.map((m) => ({
|
|
439
|
+
type: "message",
|
|
440
|
+
role: m.role || "user",
|
|
441
|
+
content: typeof m.content === "string" ? m.content : JSON.stringify(m.content ?? ""),
|
|
442
|
+
}));
|
|
443
|
+
delete body.messages;
|
|
444
|
+
} else {
|
|
445
|
+
body.input = [{ type: "message", role: "user", content: "..." }];
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// Keep role:"system" as-is — official grok-pager HAR sends system, not developer
|
|
450
|
+
// (Codex converts system→developer; Grok CLI does not).
|
|
451
|
+
normalizeGrokCliInput(body);
|
|
452
|
+
stripStoredItemReferences(body);
|
|
453
|
+
normalizeGrokCliTools(body);
|
|
454
|
+
|
|
455
|
+
// Turn index after input is finalized (user-message count, monotonic per session)
|
|
456
|
+
this._currentTurnIdx = resolveGrokCliTurnIdx(this._currentSessionId, body.input, requestKey);
|
|
71
457
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
let
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
} catch (err) {
|
|
86
|
-
log?.error?.("GROK-CLI", `Fetch failed: ${err.message}`);
|
|
87
|
-
return {
|
|
88
|
-
response: new Response(JSON.stringify({
|
|
89
|
-
error: { message: `Grok connection failed: ${err.message}`, type: "upstream_error" },
|
|
90
|
-
}), { status: 502, headers: { "Content-Type": "application/json" } }),
|
|
91
|
-
url: XAI_API,
|
|
92
|
-
headers,
|
|
93
|
-
transformedBody: upstreamBody,
|
|
94
|
-
};
|
|
458
|
+
body.stream = true;
|
|
459
|
+
body.store = false;
|
|
460
|
+
|
|
461
|
+
// Resolve upstream model id (strip effort suffix virtual models)
|
|
462
|
+
let modelEffort = resolveEffortFromModel(body.model || model);
|
|
463
|
+
let resolvedModel = body.model || model;
|
|
464
|
+
if (modelEffort) {
|
|
465
|
+
resolvedModel = resolvedModel.replace(new RegExp(`-${modelEffort}$`), "");
|
|
466
|
+
}
|
|
467
|
+
resolvedModel = getModelUpstreamId("gcli", resolvedModel) || resolvedModel;
|
|
468
|
+
// Also try provider id key
|
|
469
|
+
if (resolvedModel === (body.model || model)) {
|
|
470
|
+
resolvedModel = getModelUpstreamId("grok-cli", resolvedModel) || resolvedModel;
|
|
95
471
|
}
|
|
472
|
+
body.model = resolvedModel;
|
|
473
|
+
this._currentModel = resolvedModel;
|
|
96
474
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
475
|
+
// Reasoning effort priority: explicit > reasoning_effort > model suffix > default high.
|
|
476
|
+
// grok-build and Composer reject reasoningEffort but still accept summary/encrypted continuity.
|
|
477
|
+
const supportsReasoningEffort = supportsGrokCliReasoningEffort(resolvedModel);
|
|
478
|
+
if (!body.reasoning || typeof body.reasoning !== "object") {
|
|
479
|
+
body.reasoning = { summary: "concise" };
|
|
480
|
+
if (supportsReasoningEffort) {
|
|
481
|
+
body.reasoning.effort = normalizeGrokCliEffort(body.reasoning_effort || modelEffort);
|
|
482
|
+
}
|
|
483
|
+
} else {
|
|
484
|
+
if (supportsReasoningEffort) {
|
|
485
|
+
body.reasoning.effort = normalizeGrokCliEffort(
|
|
486
|
+
body.reasoning.effort || body.reasoning_effort || modelEffort,
|
|
487
|
+
);
|
|
488
|
+
} else {
|
|
489
|
+
delete body.reasoning.effort;
|
|
490
|
+
}
|
|
491
|
+
if (!body.reasoning.summary) body.reasoning.summary = "concise";
|
|
492
|
+
}
|
|
493
|
+
delete body.reasoning_effort;
|
|
494
|
+
|
|
495
|
+
// Encrypted reasoning for multi-turn continuity (CLI always requests this)
|
|
496
|
+
if (body.reasoning && body.reasoning.effort !== "none") {
|
|
497
|
+
const include = Array.isArray(body.include) ? body.include : [];
|
|
498
|
+
if (!include.includes("reasoning.encrypted_content")) {
|
|
499
|
+
include.push("reasoning.encrypted_content");
|
|
500
|
+
}
|
|
501
|
+
body.include = include;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// Drop Chat Completions leftovers that Responses rejects
|
|
505
|
+
delete body.messages;
|
|
506
|
+
delete body.max_tokens;
|
|
507
|
+
delete body.max_completion_tokens;
|
|
508
|
+
delete body.n;
|
|
509
|
+
delete body.seed;
|
|
510
|
+
delete body.logprobs;
|
|
511
|
+
delete body.top_logprobs;
|
|
512
|
+
delete body.frequency_penalty;
|
|
513
|
+
delete body.presence_penalty;
|
|
514
|
+
delete body.logit_bias;
|
|
515
|
+
delete body.user;
|
|
516
|
+
delete body.stream_options;
|
|
517
|
+
delete body.prompt_cache_retention;
|
|
518
|
+
delete body.safety_identifier;
|
|
519
|
+
delete body.previous_response_id; // store=false → cannot resolve
|
|
520
|
+
|
|
521
|
+
for (const k of Object.keys(body)) {
|
|
522
|
+
if (!RESPONSES_API_ALLOWLIST.has(k)) delete body[k];
|
|
114
523
|
}
|
|
115
524
|
|
|
116
|
-
|
|
117
|
-
|
|
525
|
+
return body;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
async execute(args) {
|
|
529
|
+
// Lazy-resolve stable agent id once per process if connection has none
|
|
530
|
+
if (!this._agentId && !args.credentials?.providerSpecificData?.deviceId) {
|
|
531
|
+
try {
|
|
532
|
+
const mid = await getConsistentMachineId("grok-cli-agent");
|
|
533
|
+
// Format as UUID-ish for header aesthetics
|
|
534
|
+
this._agentId = [
|
|
535
|
+
mid.slice(0, 8),
|
|
536
|
+
mid.slice(8, 12),
|
|
537
|
+
"5" + mid.slice(13, 16),
|
|
538
|
+
"a" + mid.slice(17, 20),
|
|
539
|
+
mid.slice(0, 12).padEnd(12, "0"),
|
|
540
|
+
].join("-");
|
|
541
|
+
} catch {
|
|
542
|
+
this._agentId = crypto.randomUUID();
|
|
543
|
+
}
|
|
544
|
+
} else if (args.credentials?.providerSpecificData?.deviceId) {
|
|
545
|
+
this._agentId = args.credentials.providerSpecificData.deviceId;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
return super.execute(args);
|
|
118
549
|
}
|
|
119
550
|
}
|
|
551
|
+
|
|
552
|
+
export default GrokCliExecutor;
|