@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,5 +1,7 @@
|
|
|
1
1
|
import { BaseExecutor } from "./base.js";
|
|
2
2
|
import { PROVIDERS } from "../config/providers.js";
|
|
3
|
+
import { SSE_DONE, SSE_HEADERS_NO_BUFFER } from "../utils/sseConstants.js";
|
|
4
|
+
import { sseChunk } from "../utils/sse.js";
|
|
3
5
|
|
|
4
6
|
const GROK_CHAT_API = PROVIDERS["grok-web"].baseUrl;
|
|
5
7
|
const GROK_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36";
|
|
@@ -130,10 +132,6 @@ async function* extractContent(eventStream, isThinkingModel, signal) {
|
|
|
130
132
|
yield { done: true, fingerprint, responseId };
|
|
131
133
|
}
|
|
132
134
|
|
|
133
|
-
function sseChunk(data) {
|
|
134
|
-
return `data: ${JSON.stringify(data)}\n\n`;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
135
|
function buildStreamingResponse(eventStream, model, cid, created, isThinkingModel, signal) {
|
|
138
136
|
const encoder = new TextEncoder();
|
|
139
137
|
return new ReadableStream({
|
|
@@ -175,13 +173,13 @@ function buildStreamingResponse(eventStream, model, cid, created, isThinkingMode
|
|
|
175
173
|
id: cid, object: "chat.completion.chunk", created, model, system_fingerprint: fp || null,
|
|
176
174
|
choices: [{ index: 0, delta: {}, finish_reason: "stop", logprobs: null }],
|
|
177
175
|
})));
|
|
178
|
-
controller.enqueue(encoder.encode(
|
|
176
|
+
controller.enqueue(encoder.encode(SSE_DONE));
|
|
179
177
|
} catch (err) {
|
|
180
178
|
controller.enqueue(encoder.encode(sseChunk({
|
|
181
179
|
id: cid, object: "chat.completion.chunk", created, model, system_fingerprint: null,
|
|
182
180
|
choices: [{ index: 0, delta: { content: `[Stream error: ${err.message || String(err)}]` }, finish_reason: "stop", logprobs: null }],
|
|
183
181
|
})));
|
|
184
|
-
controller.enqueue(encoder.encode(
|
|
182
|
+
controller.enqueue(encoder.encode(SSE_DONE));
|
|
185
183
|
} finally {
|
|
186
184
|
controller.close();
|
|
187
185
|
}
|
|
@@ -333,7 +331,7 @@ export class GrokWebExecutor extends BaseExecutor {
|
|
|
333
331
|
const sseStream = buildStreamingResponse(response.body, model, cid, created, isThinking, signal);
|
|
334
332
|
finalResponse = new Response(sseStream, {
|
|
335
333
|
status: 200,
|
|
336
|
-
headers: {
|
|
334
|
+
headers: { ...SSE_HEADERS_NO_BUFFER },
|
|
337
335
|
});
|
|
338
336
|
} else {
|
|
339
337
|
finalResponse = await buildNonStreamingResponse(response.body, model, cid, created, isThinking, signal);
|
|
@@ -5,6 +5,7 @@ import { GithubExecutor } from "./github.js";
|
|
|
5
5
|
import { IFlowExecutor } from "./iflow.js";
|
|
6
6
|
import { QoderExecutor } from "./qoder.js";
|
|
7
7
|
import { KiroExecutor } from "./kiro.js";
|
|
8
|
+
import { KimchiExecutor } from "./kimchi.js";
|
|
8
9
|
import { CodexExecutor } from "./codex.js";
|
|
9
10
|
import { CursorExecutor } from "./cursor.js";
|
|
10
11
|
import { VertexExecutor } from "./vertex.js";
|
|
@@ -17,6 +18,8 @@ import { PerplexityWebExecutor } from "./perplexity-web.js";
|
|
|
17
18
|
import { OllamaLocalExecutor } from "./ollama-local.js";
|
|
18
19
|
import { CommandCodeExecutor } from "./commandcode.js";
|
|
19
20
|
import { XiaomiTokenplanExecutor } from "./xiaomi-tokenplan.js";
|
|
21
|
+
import { MimoFreeExecutor } from "./mimo-free.js";
|
|
22
|
+
import { CodeBuddyExecutor } from "./codebuddy-cn.js";
|
|
20
23
|
import { DefaultExecutor } from "./default.js";
|
|
21
24
|
|
|
22
25
|
const executors = {
|
|
@@ -27,6 +30,7 @@ const executors = {
|
|
|
27
30
|
iflow: new IFlowExecutor(),
|
|
28
31
|
qoder: new QoderExecutor(),
|
|
29
32
|
kiro: new KiroExecutor(),
|
|
33
|
+
kimchi: new KimchiExecutor(),
|
|
30
34
|
codex: new CodexExecutor(),
|
|
31
35
|
cursor: new CursorExecutor(),
|
|
32
36
|
cu: new CursorExecutor(), // Alias for cursor
|
|
@@ -37,10 +41,15 @@ const executors = {
|
|
|
37
41
|
"opencode-go": new OpenCodeGoExecutor(),
|
|
38
42
|
"grok-web": new GrokWebExecutor(),
|
|
39
43
|
"grok-cli": new GrokCliExecutor(),
|
|
44
|
+
gcli: new GrokCliExecutor(), // Alias
|
|
45
|
+
gb: new GrokCliExecutor(), // Alias (Grok Build)
|
|
40
46
|
"perplexity-web": new PerplexityWebExecutor(),
|
|
41
47
|
"ollama-local": new OllamaLocalExecutor(),
|
|
42
48
|
commandcode: new CommandCodeExecutor(),
|
|
43
49
|
"xiaomi-tokenplan": new XiaomiTokenplanExecutor(),
|
|
50
|
+
"mimo-free": new MimoFreeExecutor(),
|
|
51
|
+
mmf: new MimoFreeExecutor(), // Alias for mimo-free
|
|
52
|
+
"codebuddy-cn": new CodeBuddyExecutor(),
|
|
44
53
|
};
|
|
45
54
|
|
|
46
55
|
const defaultCache = new Map();
|
|
@@ -63,6 +72,7 @@ export { GithubExecutor } from "./github.js";
|
|
|
63
72
|
export { IFlowExecutor } from "./iflow.js";
|
|
64
73
|
export { QoderExecutor } from "./qoder.js";
|
|
65
74
|
export { KiroExecutor } from "./kiro.js";
|
|
75
|
+
export { KimchiExecutor } from "./kimchi.js";
|
|
66
76
|
export { CodexExecutor } from "./codex.js";
|
|
67
77
|
export { CursorExecutor } from "./cursor.js";
|
|
68
78
|
export { VertexExecutor } from "./vertex.js";
|
|
@@ -76,3 +86,5 @@ export { PerplexityWebExecutor } from "./perplexity-web.js";
|
|
|
76
86
|
export { OllamaLocalExecutor } from "./ollama-local.js";
|
|
77
87
|
export { CommandCodeExecutor } from "./commandcode.js";
|
|
78
88
|
export { XiaomiTokenplanExecutor } from "./xiaomi-tokenplan.js";
|
|
89
|
+
export { MimoFreeExecutor } from "./mimo-free.js";
|
|
90
|
+
export { CodeBuddyExecutor } from "./codebuddy-cn.js";
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { BaseExecutor } from "./base.js";
|
|
2
2
|
import { PROVIDERS } from "../config/providers.js";
|
|
3
|
+
import { resolveKiroModel } from "../config/kiroConstants.js";
|
|
3
4
|
import { v4 as uuidv4 } from "uuid";
|
|
4
5
|
import { refreshKiroToken } from "../services/tokenRefresh.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
6
|
+
import { SSE_DONE, SSE_HEADERS } from "../utils/sseConstants.js";
|
|
7
|
+
import { getCapabilitiesForModel } from "../providers/capabilities.js";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* KiroExecutor - Executor for Kiro AI (AWS CodeWhisperer)
|
|
@@ -21,57 +22,99 @@ export class KiroExecutor extends BaseExecutor {
|
|
|
21
22
|
"Amz-Sdk-Invocation-Id": uuidv4()
|
|
22
23
|
};
|
|
23
24
|
|
|
24
|
-
|
|
25
|
+
// API-key auth: the key is stored as accessToken and sent as a bearer token
|
|
26
|
+
// exactly like an OAuth access token, but with an extra `tokentype: API_KEY`
|
|
27
|
+
// header so CodeWhisperer treats it as a long-lived API key rather than an
|
|
28
|
+
// OIDC/social access token. Mirrors the Kiro IDE headless-auth behavior.
|
|
29
|
+
// Enterprise / Microsoft Entra (external_idp) tokens are OAuth access tokens,
|
|
30
|
+
// but CodeWhisperer requires TokenType=EXTERNAL_IDP to bind them to profiles.
|
|
31
|
+
const authMethod = credentials?.providerSpecificData?.authMethod;
|
|
32
|
+
const isApiKey = authMethod === "api_key";
|
|
33
|
+
const isExternalIdp = authMethod === "external_idp";
|
|
34
|
+
|
|
35
|
+
const apiKey = credentials?.apiKey || (isApiKey ? credentials?.accessToken : null);
|
|
36
|
+
if (isApiKey && apiKey) {
|
|
37
|
+
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
38
|
+
headers["tokentype"] = "API_KEY";
|
|
39
|
+
} else if (credentials.accessToken) {
|
|
25
40
|
headers["Authorization"] = `Bearer ${credentials.accessToken}`;
|
|
41
|
+
if (isExternalIdp) {
|
|
42
|
+
headers["TokenType"] = "EXTERNAL_IDP";
|
|
43
|
+
}
|
|
26
44
|
}
|
|
27
45
|
|
|
28
46
|
return headers;
|
|
29
47
|
}
|
|
30
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Auth-aware endpoint ordering.
|
|
51
|
+
*
|
|
52
|
+
* API-key Kiro connections store a raw CodeWhisperer credential (validated
|
|
53
|
+
* against codewhisperer.us-east-1.amazonaws.com via ListAvailableProfiles).
|
|
54
|
+
* The Kiro IDE gateway (runtime.*.kiro.dev) expects Kiro OIDC/social tokens
|
|
55
|
+
* and rejects an `tokentype: API_KEY` token with 401/403 — which
|
|
56
|
+
* BaseExecutor.execute() returns immediately (only 429 / network errors fall
|
|
57
|
+
* through to the next host). So for api-key auth we must try the *.amazonaws.com
|
|
58
|
+
* CodeWhisperer hosts FIRST, mirroring the Kiro-Go reference fork which never
|
|
59
|
+
* routes api-key traffic through kiro.dev. External IdP enterprise tokens also
|
|
60
|
+
* use the CodeWhisperer surface, with the `TokenType: EXTERNAL_IDP` header.
|
|
61
|
+
* Other OAuth methods keep the default order (kiro.dev first) since their
|
|
62
|
+
* tokens are what that gateway accepts.
|
|
63
|
+
*/
|
|
64
|
+
getOrderedBaseUrls(credentials) {
|
|
65
|
+
const baseUrls = this.getBaseUrls();
|
|
66
|
+
const authMethod = credentials?.providerSpecificData?.authMethod;
|
|
67
|
+
// IAM Identity Center (idc) tokens are AWS SSO access tokens — the same
|
|
68
|
+
// family as external_idp/api_key. The kiro.dev gateway rejects them with
|
|
69
|
+
// 403 "bearer token invalid", so they must hit the CodeWhisperer
|
|
70
|
+
// *.amazonaws.com surface, and in the region the token was minted in
|
|
71
|
+
// (the baseUrls are hardcoded us-east-1).
|
|
72
|
+
const isCodeWhispererSurface =
|
|
73
|
+
authMethod === "api_key" || authMethod === "external_idp" || authMethod === "idc";
|
|
74
|
+
if (!isCodeWhispererSurface) return baseUrls;
|
|
75
|
+
|
|
76
|
+
const region = (credentials?.providerSpecificData?.region || "us-east-1").trim();
|
|
77
|
+
const regionalize = (u) =>
|
|
78
|
+
region && region !== "us-east-1" && u.includes("amazonaws.com")
|
|
79
|
+
? u.replace(/([a-z]+)\.[a-z0-9-]+\.amazonaws\.com/, `$1.${region}.amazonaws.com`)
|
|
80
|
+
: u;
|
|
81
|
+
|
|
82
|
+
const amazon = baseUrls.filter((u) => u.includes("amazonaws.com")).map(regionalize);
|
|
83
|
+
const others = baseUrls.filter((u) => !u.includes("amazonaws.com"));
|
|
84
|
+
return amazon.length > 0 ? [...amazon, ...others] : baseUrls;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
buildUrl(model, stream, urlIndex = 0, credentials = null) {
|
|
88
|
+
const baseUrls = this.getOrderedBaseUrls(credentials);
|
|
89
|
+
return baseUrls[urlIndex] || baseUrls[0] || this.config.baseUrl;
|
|
90
|
+
}
|
|
91
|
+
|
|
31
92
|
transformRequest(model, body, stream, credentials) {
|
|
32
93
|
return body;
|
|
33
94
|
}
|
|
34
95
|
|
|
35
96
|
/**
|
|
36
|
-
*
|
|
97
|
+
* Kiro execute — delegate to BaseExecutor for endpoint fallback + retry, then
|
|
98
|
+
* transform the binary AWS EventStream into OpenAI-shaped SSE on success.
|
|
99
|
+
*
|
|
100
|
+
* BaseExecutor.execute() walks config.baseUrls (runtime.us-east-1.kiro.dev →
|
|
101
|
+
* codewhisperer → q) advancing to the next host on 429 (shouldRetry) and on
|
|
102
|
+
* network/5xx errors, while tryRetry handles in-place retries per `retry: {429: 2}`.
|
|
103
|
+
* Note: api-key connections reorder these so the *.amazonaws.com hosts come
|
|
104
|
+
* first — see getOrderedBaseUrls/buildUrl above.
|
|
105
|
+
* Note: the baseUrls are alternate surfaces of one regional service, so rotation
|
|
106
|
+
* is edge-level failover — it does not grant fresh 429 quota. Per-account 429
|
|
107
|
+
* spreading is handled upstream by account rotation in sse/handlers/chat.js.
|
|
108
|
+
*
|
|
109
|
+
* Errors are returned untransformed so the upstream handler can read the body,
|
|
110
|
+
* classify the status, and trigger account fallback/cooldown.
|
|
37
111
|
*/
|
|
38
|
-
async execute(
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
// Merge default retry config with provider-specific config
|
|
43
|
-
const retryConfig = { ...DEFAULT_RETRY_CONFIG, ...this.config.retry };
|
|
44
|
-
let retryAttempts = 0;
|
|
45
|
-
|
|
46
|
-
while (true) {
|
|
47
|
-
const headers = this.buildHeaders(credentials, stream);
|
|
48
|
-
|
|
49
|
-
const response = await proxyAwareFetch(url, {
|
|
50
|
-
method: "POST",
|
|
51
|
-
headers,
|
|
52
|
-
body: JSON.stringify(transformedBody),
|
|
53
|
-
signal
|
|
54
|
-
}, proxyOptions);
|
|
55
|
-
|
|
56
|
-
// Check if should retry based on status code
|
|
57
|
-
const { attempts: maxRetries, delayMs } = resolveRetryEntry(retryConfig[response.status]);
|
|
58
|
-
if (!response.ok && maxRetries > 0 && retryAttempts < maxRetries) {
|
|
59
|
-
retryAttempts++;
|
|
60
|
-
log?.debug?.("RETRY", `${response.status} retry ${retryAttempts}/${maxRetries} after ${delayMs / 1000}s`);
|
|
61
|
-
await new Promise(resolve => setTimeout(resolve, delayMs));
|
|
62
|
-
continue;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (!response.ok) {
|
|
66
|
-
return { response, url, headers, transformedBody };
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Success - transform and return
|
|
70
|
-
// For Kiro, we need to transform the binary EventStream to SSE
|
|
71
|
-
// Create a TransformStream to convert binary to SSE text
|
|
72
|
-
const transformedResponse = this.transformEventStreamToSSE(response, model);
|
|
73
|
-
return { response: transformedResponse, url, headers, transformedBody };
|
|
112
|
+
async execute(args) {
|
|
113
|
+
const result = await super.execute(args);
|
|
114
|
+
if (result?.response?.ok) {
|
|
115
|
+
result.response = this.transformEventStreamToSSE(result.response, args.model);
|
|
74
116
|
}
|
|
117
|
+
return result;
|
|
75
118
|
}
|
|
76
119
|
|
|
77
120
|
/**
|
|
@@ -83,6 +126,8 @@ export class KiroExecutor extends BaseExecutor {
|
|
|
83
126
|
let chunkIndex = 0;
|
|
84
127
|
const responseId = `chatcmpl-${Date.now()}`;
|
|
85
128
|
const created = Math.floor(Date.now() / 1000);
|
|
129
|
+
const capabilityModel = resolveKiroModel(model).upstream;
|
|
130
|
+
const contextWindow = getCapabilitiesForModel("kiro", capabilityModel).contextWindow || 200000;
|
|
86
131
|
const state = {
|
|
87
132
|
endDetected: false,
|
|
88
133
|
finishEmitted: false,
|
|
@@ -90,11 +135,14 @@ export class KiroExecutor extends BaseExecutor {
|
|
|
90
135
|
hasReasoningContent: false,
|
|
91
136
|
reasoningChunkCount: 0,
|
|
92
137
|
toolCallIndex: 0,
|
|
93
|
-
seenToolIds: new Map()
|
|
138
|
+
seenToolIds: new Map(),
|
|
139
|
+
inThinking: false
|
|
94
140
|
};
|
|
95
141
|
|
|
96
142
|
const transformStream = new TransformStream({
|
|
97
143
|
async transform(chunk, controller) {
|
|
144
|
+
// Track output so we can emit a keepalive if this frame yields no chunk.
|
|
145
|
+
const enqueueCountBefore = chunkIndex;
|
|
98
146
|
// Append to buffer
|
|
99
147
|
const newBuffer = new Uint8Array(buffer.length + chunk.length);
|
|
100
148
|
newBuffer.set(buffer);
|
|
@@ -118,16 +166,45 @@ export class KiroExecutor extends BaseExecutor {
|
|
|
118
166
|
if (!event) continue;
|
|
119
167
|
|
|
120
168
|
const eventType = event.headers[":event-type"] || "";
|
|
121
|
-
|
|
169
|
+
|
|
122
170
|
// Track total content length for token estimation
|
|
123
171
|
if (!state.totalContentLength) state.totalContentLength = 0;
|
|
124
172
|
if (!state.contextUsagePercentage) state.contextUsagePercentage = 0;
|
|
125
173
|
|
|
126
174
|
// Handle assistantResponseEvent
|
|
127
175
|
if (eventType === "assistantResponseEvent" && event.payload?.content) {
|
|
128
|
-
|
|
176
|
+
let content = event.payload.content;
|
|
177
|
+
|
|
178
|
+
// Kiro Claude models can leak <thinking> blocks into the content stream.
|
|
179
|
+
// We strip these literal tags to prevent duplication, as the reasoning
|
|
180
|
+
// is already routed correctly via reasoningContentEvent.
|
|
181
|
+
if (state.inThinking) {
|
|
182
|
+
if (content.includes("</thinking>")) {
|
|
183
|
+
state.inThinking = false;
|
|
184
|
+
const after = content.split("</thinking>").slice(1).join("</thinking>");
|
|
185
|
+
content = after.startsWith("\n") ? after.substring(1) : after;
|
|
186
|
+
} else {
|
|
187
|
+
content = ""; // Drop entirely while inside thinking block
|
|
188
|
+
}
|
|
189
|
+
} else if (content.includes("<thinking>")) {
|
|
190
|
+
state.inThinking = true;
|
|
191
|
+
if (content.includes("</thinking>")) {
|
|
192
|
+
state.inThinking = false;
|
|
193
|
+
const before = content.split("<thinking>")[0];
|
|
194
|
+
const after = content.split("</thinking>").slice(1).join("</thinking>");
|
|
195
|
+
content = before + (after.startsWith("\n") ? after.substring(1) : after);
|
|
196
|
+
} else {
|
|
197
|
+
content = content.split("<thinking>")[0];
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (!content && state.hasReasoningContent) {
|
|
202
|
+
// If we stripped everything, skip emitting an empty content chunk
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
|
|
129
206
|
state.totalContentLength += content.length;
|
|
130
|
-
|
|
207
|
+
|
|
131
208
|
const chunk = {
|
|
132
209
|
id: responseId,
|
|
133
210
|
object: "chat.completion.chunk",
|
|
@@ -314,13 +391,24 @@ export class KiroExecutor extends BaseExecutor {
|
|
|
314
391
|
if (metrics && typeof metrics === 'object') {
|
|
315
392
|
const inputTokens = metrics.inputTokens || 0;
|
|
316
393
|
const outputTokens = metrics.outputTokens || 0;
|
|
317
|
-
|
|
394
|
+
// ponytail: Amazon Q upstream does not expose cache fields today,
|
|
395
|
+
// but pick up cache_read_input_tokens / cache_creation_input_tokens
|
|
396
|
+
// if the event shape grows them so cost tracking stays accurate.
|
|
397
|
+
const cachedTokens = metrics.cacheReadInputTokens || metrics.cache_read_input_tokens || 0;
|
|
398
|
+
const cacheCreationInputTokens = metrics.cacheCreationInputTokens || metrics.cache_creation_input_tokens || 0;
|
|
399
|
+
|
|
318
400
|
if (inputTokens > 0 || outputTokens > 0) {
|
|
319
401
|
state.usage = {
|
|
320
402
|
prompt_tokens: inputTokens,
|
|
321
403
|
completion_tokens: outputTokens,
|
|
322
404
|
total_tokens: inputTokens + outputTokens
|
|
323
405
|
};
|
|
406
|
+
// Kiro is Claude-backed: inputTokens EXCLUDES cache (Claude convention),
|
|
407
|
+
// not inclusive like OpenAI's cached_tokens. Emit cache_read_input_tokens
|
|
408
|
+
// (not cached_tokens) so canonicalizeUsage takes the Claude fold path and
|
|
409
|
+
// correctly adds cache back into prompt_tokens instead of undercharging.
|
|
410
|
+
if (cachedTokens > 0) state.usage.cache_read_input_tokens = cachedTokens;
|
|
411
|
+
if (cacheCreationInputTokens > 0) state.usage.cache_creation_input_tokens = cacheCreationInputTokens;
|
|
324
412
|
}
|
|
325
413
|
}
|
|
326
414
|
}
|
|
@@ -328,27 +416,26 @@ export class KiroExecutor extends BaseExecutor {
|
|
|
328
416
|
// Emit final chunk only after receiving BOTH meteringEvent AND contextUsageEvent
|
|
329
417
|
if (state.hasMeteringEvent && state.hasContextUsage && !state.finishEmitted) {
|
|
330
418
|
state.finishEmitted = true;
|
|
331
|
-
|
|
419
|
+
|
|
332
420
|
// Estimate tokens if not available from events
|
|
333
421
|
if (!state.usage) {
|
|
334
422
|
// Estimate output tokens from content length
|
|
335
|
-
const estimatedOutputTokens = state.totalContentLength > 0
|
|
423
|
+
const estimatedOutputTokens = state.totalContentLength > 0
|
|
336
424
|
? Math.max(1, Math.floor(state.totalContentLength / 4))
|
|
337
425
|
: 0;
|
|
338
|
-
|
|
426
|
+
|
|
339
427
|
// Estimate input tokens from contextUsagePercentage
|
|
340
|
-
// Kiro models typically have 200k context window
|
|
341
428
|
const estimatedInputTokens = state.contextUsagePercentage > 0
|
|
342
|
-
? Math.floor(state.contextUsagePercentage *
|
|
429
|
+
? Math.floor(state.contextUsagePercentage * contextWindow / 100)
|
|
343
430
|
: 0;
|
|
344
|
-
|
|
431
|
+
|
|
345
432
|
state.usage = {
|
|
346
433
|
prompt_tokens: estimatedInputTokens,
|
|
347
434
|
completion_tokens: estimatedOutputTokens,
|
|
348
435
|
total_tokens: estimatedInputTokens + estimatedOutputTokens
|
|
349
436
|
};
|
|
350
437
|
}
|
|
351
|
-
|
|
438
|
+
|
|
352
439
|
const finishChunk = {
|
|
353
440
|
id: responseId,
|
|
354
441
|
object: "chat.completion.chunk",
|
|
@@ -360,12 +447,12 @@ export class KiroExecutor extends BaseExecutor {
|
|
|
360
447
|
finish_reason: state.hasToolCalls ? "tool_calls" : "stop"
|
|
361
448
|
}]
|
|
362
449
|
};
|
|
363
|
-
|
|
450
|
+
|
|
364
451
|
// Include usage in final chunk if available
|
|
365
452
|
if (state.usage) {
|
|
366
453
|
finishChunk.usage = state.usage;
|
|
367
454
|
}
|
|
368
|
-
|
|
455
|
+
|
|
369
456
|
controller.enqueue(new TextEncoder().encode(`data: ${JSON.stringify(finishChunk)}\n\n`));
|
|
370
457
|
}
|
|
371
458
|
}
|
|
@@ -373,6 +460,12 @@ export class KiroExecutor extends BaseExecutor {
|
|
|
373
460
|
if (iterations >= maxIterations) {
|
|
374
461
|
console.warn("[Kiro] Max iterations reached in event parsing");
|
|
375
462
|
}
|
|
463
|
+
|
|
464
|
+
// No client chunk produced this frame — emit an SSE comment keepalive
|
|
465
|
+
// so the stall watchdog sees upstream activity (ignored by parser/client).
|
|
466
|
+
if (chunkIndex === enqueueCountBefore && !state.finishEmitted) {
|
|
467
|
+
controller.enqueue(new TextEncoder().encode(": ka\n\n"));
|
|
468
|
+
}
|
|
376
469
|
},
|
|
377
470
|
|
|
378
471
|
flush(controller) {
|
|
@@ -394,24 +487,20 @@ export class KiroExecutor extends BaseExecutor {
|
|
|
394
487
|
}
|
|
395
488
|
|
|
396
489
|
// Send final done message
|
|
397
|
-
controller.enqueue(new TextEncoder().encode(
|
|
490
|
+
controller.enqueue(new TextEncoder().encode(SSE_DONE));
|
|
398
491
|
}
|
|
399
492
|
});
|
|
400
493
|
|
|
401
494
|
// Pipe response body through transform stream
|
|
402
495
|
if (!response.body) {
|
|
403
|
-
return new Response(
|
|
496
|
+
return new Response(SSE_DONE, { status: response.status, headers: { "Content-Type": "text/event-stream" } });
|
|
404
497
|
}
|
|
405
498
|
const transformedStream = response.body.pipeThrough(transformStream);
|
|
406
499
|
|
|
407
500
|
return new Response(transformedStream, {
|
|
408
501
|
status: response.status,
|
|
409
502
|
statusText: response.statusText,
|
|
410
|
-
headers: {
|
|
411
|
-
"Content-Type": "text/event-stream",
|
|
412
|
-
"Cache-Control": "no-cache",
|
|
413
|
-
"Connection": "keep-alive"
|
|
414
|
-
}
|
|
503
|
+
headers: { ...SSE_HEADERS }
|
|
415
504
|
});
|
|
416
505
|
}
|
|
417
506
|
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import { BaseExecutor } from "./base.js";
|
|
2
2
|
import { PROVIDERS } from "../config/providers.js";
|
|
3
3
|
import { injectReasoningContent } from "../utils/reasoningContentInjector.js";
|
|
4
|
+
import { ANTHROPIC_API_VERSION } from "../providers/shared.js";
|
|
4
5
|
|
|
5
6
|
// Models that use /zen/go/v1/messages (Anthropic/Claude format + x-api-key auth)
|
|
6
|
-
const
|
|
7
|
+
const MESSAGES_FORMAT_MODELS = new Set([
|
|
8
|
+
"minimax-m3",
|
|
9
|
+
"minimax-m2.7",
|
|
10
|
+
"minimax-m2.5",
|
|
11
|
+
"qwen3.7-max",
|
|
12
|
+
"qwen3.7-plus",
|
|
13
|
+
"qwen3.6-plus",
|
|
14
|
+
]);
|
|
7
15
|
|
|
8
16
|
const BASE = "https://opencode.ai/zen/go/v1";
|
|
9
17
|
|
|
@@ -15,7 +23,7 @@ export class OpenCodeGoExecutor extends BaseExecutor {
|
|
|
15
23
|
// buildUrl runs before buildHeaders in BaseExecutor.execute, cache model here
|
|
16
24
|
buildUrl(model) {
|
|
17
25
|
this._lastModel = model;
|
|
18
|
-
return
|
|
26
|
+
return MESSAGES_FORMAT_MODELS.has(model)
|
|
19
27
|
? `${BASE}/messages`
|
|
20
28
|
: `${BASE}/chat/completions`;
|
|
21
29
|
}
|
|
@@ -24,9 +32,9 @@ export class OpenCodeGoExecutor extends BaseExecutor {
|
|
|
24
32
|
const key = credentials?.apiKey || credentials?.accessToken;
|
|
25
33
|
const headers = { "Content-Type": "application/json" };
|
|
26
34
|
|
|
27
|
-
if (
|
|
35
|
+
if (MESSAGES_FORMAT_MODELS.has(this._lastModel)) {
|
|
28
36
|
headers["x-api-key"] = key;
|
|
29
|
-
headers["anthropic-version"] =
|
|
37
|
+
headers["anthropic-version"] = ANTHROPIC_API_VERSION;
|
|
30
38
|
} else {
|
|
31
39
|
headers["Authorization"] = `Bearer ${key}`;
|
|
32
40
|
}
|
|
@@ -15,7 +15,7 @@ export class OpenCodeExecutor extends BaseExecutor {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
buildUrl(model) {
|
|
18
|
-
const base =
|
|
18
|
+
const base = this.config.baseUrl;
|
|
19
19
|
return MESSAGES_MODELS.has(model)
|
|
20
20
|
? `${base}/zen/v1/messages`
|
|
21
21
|
: `${base}/zen/v1/chat/completions`;
|