@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,6 +1,7 @@
|
|
|
1
1
|
import { BaseExecutor } from "./base.js";
|
|
2
2
|
import { PROVIDERS } from "../config/providers.js";
|
|
3
|
-
import {
|
|
3
|
+
import { SSE_DONE, SSE_HEADERS_NO_BUFFER } from "../utils/sseConstants.js";
|
|
4
|
+
import { sseChunk } from "../utils/sse.js";
|
|
4
5
|
|
|
5
6
|
const PPLX_SSE_ENDPOINT = PROVIDERS["perplexity-web"].baseUrl;
|
|
6
7
|
const PPLX_API_VERSION = "2.18";
|
|
@@ -145,24 +146,6 @@ function parseOpenAIMessages(messages) {
|
|
|
145
146
|
else if (Array.isArray(msg.content)) {
|
|
146
147
|
content = msg.content.filter((c) => c.type === "text").map((c) => String(c.text || "")).join(" ");
|
|
147
148
|
}
|
|
148
|
-
|
|
149
|
-
// Handle tool role messages — convert to user message with tool result context
|
|
150
|
-
if (role === "tool") {
|
|
151
|
-
const toolName = msg.name || "unknown_tool";
|
|
152
|
-
const toolCallId = msg.tool_call_id || "";
|
|
153
|
-
content = `[Tool Result for ${toolName}${toolCallId ? ` (call_id: ${toolCallId})` : ""}]:\n${content || "(empty result)"}`;
|
|
154
|
-
role = "user";
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// Handle assistant messages with tool_calls — serialize them as text
|
|
158
|
-
if (role === "assistant" && msg.tool_calls && !content) {
|
|
159
|
-
const tcText = msg.tool_calls.map(tc => {
|
|
160
|
-
const fn = tc.function || {};
|
|
161
|
-
return `<tool_call>{"name":"${fn.name}","arguments":${fn.arguments || "{}"}}</tool_call>`;
|
|
162
|
-
}).join("\n");
|
|
163
|
-
content = tcText;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
149
|
if (!content.trim()) continue;
|
|
167
150
|
if (role === "system") systemMsg += content + "\n";
|
|
168
151
|
else if (role === "user" || role === "assistant") history.push({ role, content });
|
|
@@ -200,37 +183,13 @@ function buildPplxRequestBody(query, mode, modelPref, followUpUuid) {
|
|
|
200
183
|
|
|
201
184
|
function formatToolsHint(tools) {
|
|
202
185
|
if (!Array.isArray(tools) || tools.length === 0) return "";
|
|
203
|
-
const
|
|
186
|
+
const lines = tools.map((t) => {
|
|
204
187
|
const fn = t?.function || t || {};
|
|
205
188
|
const name = fn.name || "unnamed";
|
|
206
|
-
const desc = fn.description || "";
|
|
207
|
-
|
|
208
|
-
return `{"name":"${name}","description":${JSON.stringify(desc)},"parameters":${params}}`;
|
|
189
|
+
const desc = (fn.description || "").split("\n")[0].slice(0, 200);
|
|
190
|
+
return `- ${name}: ${desc}`;
|
|
209
191
|
});
|
|
210
|
-
return `
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// Parse tool calls from Perplexity text response
|
|
214
|
-
const TOOL_CALL_RE = /<tool_call>\s*([\s\S]*?)\s*<\/tool_call>/g;
|
|
215
|
-
function parseToolCalls(text) {
|
|
216
|
-
const calls = [];
|
|
217
|
-
let match;
|
|
218
|
-
while ((match = TOOL_CALL_RE.exec(text)) !== null) {
|
|
219
|
-
try {
|
|
220
|
-
const obj = JSON.parse(match[1]);
|
|
221
|
-
if (obj.name) {
|
|
222
|
-
calls.push({
|
|
223
|
-
id: `call_${Math.random().toString(36).slice(2, 14)}`,
|
|
224
|
-
type: "function",
|
|
225
|
-
function: { name: obj.name, arguments: JSON.stringify(obj.arguments || {}) },
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
} catch { /* skip malformed */ }
|
|
229
|
-
}
|
|
230
|
-
return calls;
|
|
231
|
-
}
|
|
232
|
-
function stripToolCallTags(text) {
|
|
233
|
-
return text.replace(/<tool_call>[\s\S]*?<\/tool_call>/g, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
192
|
+
return `Available tools (reference only, cannot invoke):\n${lines.join("\n")}`;
|
|
234
193
|
}
|
|
235
194
|
|
|
236
195
|
function buildQuery(parsed, followUpUuid, tools) {
|
|
@@ -332,10 +291,6 @@ async function* extractContent(eventStream, signal) {
|
|
|
332
291
|
yield { delta: "", answer: fullAnswer, backendUuid: backendUuid ?? undefined, done: true };
|
|
333
292
|
}
|
|
334
293
|
|
|
335
|
-
function sseChunk(data) {
|
|
336
|
-
return `data: ${JSON.stringify(data)}\n\n`;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
294
|
function buildStreamingResponse(eventStream, model, cid, created, history, currentMsg, signal) {
|
|
340
295
|
const encoder = new TextEncoder();
|
|
341
296
|
return new ReadableStream({
|
|
@@ -379,37 +334,19 @@ function buildStreamingResponse(eventStream, model, cid, created, history, curre
|
|
|
379
334
|
if (chunk.answer) fullAnswer = chunk.answer;
|
|
380
335
|
}
|
|
381
336
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
// Emit tool calls as delta chunks
|
|
388
|
-
for (const tc of toolCalls) {
|
|
389
|
-
controller.enqueue(encoder.encode(sseChunk({
|
|
390
|
-
id: cid, object: "chat.completion.chunk", created, model, system_fingerprint: null,
|
|
391
|
-
choices: [{ index: 0, delta: { tool_calls: [tc] }, finish_reason: null, logprobs: null }],
|
|
392
|
-
})));
|
|
393
|
-
}
|
|
394
|
-
controller.enqueue(encoder.encode(sseChunk({
|
|
395
|
-
id: cid, object: "chat.completion.chunk", created, model, system_fingerprint: null,
|
|
396
|
-
choices: [{ index: 0, delta: {}, finish_reason: "tool_calls", logprobs: null }],
|
|
397
|
-
})));
|
|
398
|
-
} else {
|
|
399
|
-
controller.enqueue(encoder.encode(sseChunk({
|
|
400
|
-
id: cid, object: "chat.completion.chunk", created, model, system_fingerprint: null,
|
|
401
|
-
choices: [{ index: 0, delta: {}, finish_reason: "stop", logprobs: null }],
|
|
402
|
-
})));
|
|
403
|
-
}
|
|
404
|
-
controller.enqueue(encoder.encode("data: [DONE]\n\n"));
|
|
337
|
+
controller.enqueue(encoder.encode(sseChunk({
|
|
338
|
+
id: cid, object: "chat.completion.chunk", created, model, system_fingerprint: null,
|
|
339
|
+
choices: [{ index: 0, delta: {}, finish_reason: "stop", logprobs: null }],
|
|
340
|
+
})));
|
|
341
|
+
controller.enqueue(encoder.encode(SSE_DONE));
|
|
405
342
|
|
|
406
|
-
sessionStore(history, currentMsg, cleanResponse(
|
|
343
|
+
sessionStore(history, currentMsg, cleanResponse(fullAnswer), respBackendUuid);
|
|
407
344
|
} catch (err) {
|
|
408
345
|
controller.enqueue(encoder.encode(sseChunk({
|
|
409
346
|
id: cid, object: "chat.completion.chunk", created, model, system_fingerprint: null,
|
|
410
347
|
choices: [{ index: 0, delta: { content: `[Stream error: ${err.message || String(err)}]` }, finish_reason: "stop", logprobs: null }],
|
|
411
348
|
})));
|
|
412
|
-
controller.enqueue(encoder.encode(
|
|
349
|
+
controller.enqueue(encoder.encode(SSE_DONE));
|
|
413
350
|
} finally {
|
|
414
351
|
controller.close();
|
|
415
352
|
}
|
|
@@ -435,27 +372,14 @@ async function buildNonStreamingResponse(eventStream, model, cid, created, histo
|
|
|
435
372
|
}
|
|
436
373
|
|
|
437
374
|
fullAnswer = cleanResponse(fullAnswer);
|
|
438
|
-
sessionStore(history, currentMsg,
|
|
375
|
+
sessionStore(history, currentMsg, fullAnswer, respBackendUuid);
|
|
439
376
|
|
|
440
377
|
const reasoningContent = thinkingParts.length > 0 ? thinkingParts.join("\n") : undefined;
|
|
441
|
-
const
|
|
442
|
-
|
|
378
|
+
const msg = { role: "assistant", content: fullAnswer };
|
|
379
|
+
if (reasoningContent) msg.reasoning_content = reasoningContent;
|
|
443
380
|
|
|
444
381
|
const promptTokens = Math.ceil(currentMsg.length / 4);
|
|
445
|
-
const completionTokens = Math.ceil(
|
|
446
|
-
|
|
447
|
-
if (toolCalls.length > 0) {
|
|
448
|
-
const msg = { role: "assistant", content: cleanAnswer || null, tool_calls: toolCalls };
|
|
449
|
-
if (reasoningContent) msg.reasoning_content = reasoningContent;
|
|
450
|
-
return new Response(JSON.stringify({
|
|
451
|
-
id: cid, object: "chat.completion", created, model, system_fingerprint: null,
|
|
452
|
-
choices: [{ index: 0, message: msg, finish_reason: "tool_calls", logprobs: null }],
|
|
453
|
-
usage: { prompt_tokens: promptTokens, completion_tokens: completionTokens, total_tokens: promptTokens + completionTokens },
|
|
454
|
-
}), { status: 200, headers: { "Content-Type": "application/json" } });
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
const msg = { role: "assistant", content: cleanAnswer };
|
|
458
|
-
if (reasoningContent) msg.reasoning_content = reasoningContent;
|
|
382
|
+
const completionTokens = Math.ceil(fullAnswer.length / 4);
|
|
459
383
|
|
|
460
384
|
return new Response(JSON.stringify({
|
|
461
385
|
id: cid, object: "chat.completion", created, model, system_fingerprint: null,
|
|
@@ -469,7 +393,7 @@ export class PerplexityWebExecutor extends BaseExecutor {
|
|
|
469
393
|
super("perplexity-web", PROVIDERS["perplexity-web"]);
|
|
470
394
|
}
|
|
471
395
|
|
|
472
|
-
async execute({ model, body, stream, credentials, signal, log
|
|
396
|
+
async execute({ model, body, stream, credentials, signal, log }) {
|
|
473
397
|
const messages = body?.messages;
|
|
474
398
|
if (!messages || !Array.isArray(messages) || messages.length === 0) {
|
|
475
399
|
const errResp = new Response(JSON.stringify({
|
|
@@ -531,7 +455,7 @@ export class PerplexityWebExecutor extends BaseExecutor {
|
|
|
531
455
|
|
|
532
456
|
let response;
|
|
533
457
|
try {
|
|
534
|
-
response = await
|
|
458
|
+
response = await fetch(PPLX_SSE_ENDPOINT, fetchOptions);
|
|
535
459
|
} catch (err) {
|
|
536
460
|
log?.error?.("PPLX-WEB", `Fetch failed: ${err.message || String(err)}`);
|
|
537
461
|
const errResp = new Response(JSON.stringify({
|
|
@@ -567,7 +491,7 @@ export class PerplexityWebExecutor extends BaseExecutor {
|
|
|
567
491
|
const sseStream = buildStreamingResponse(response.body, model, cid, created, parsed.history, parsed.currentMsg, signal);
|
|
568
492
|
finalResponse = new Response(sseStream, {
|
|
569
493
|
status: 200,
|
|
570
|
-
headers: {
|
|
494
|
+
headers: { ...SSE_HEADERS_NO_BUFFER },
|
|
571
495
|
});
|
|
572
496
|
} else {
|
|
573
497
|
finalResponse = await buildNonStreamingResponse(response.body, model, cid, created, parsed.history, parsed.currentMsg, signal);
|
|
@@ -20,18 +20,20 @@
|
|
|
20
20
|
* different model upstream, so a missing entry is a hard error.
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
-
import { qoderEncodeBody } from
|
|
24
|
-
import { buildCosyHeaders } from
|
|
23
|
+
import { qoderEncodeBody } from "../shared/qoder/encoding.js";
|
|
24
|
+
import { buildCosyHeaders } from "../shared/qoder/cosy.js";
|
|
25
25
|
import { v4 as uuidv4 } from "uuid";
|
|
26
26
|
import { createHash } from "crypto";
|
|
27
27
|
|
|
28
28
|
import { BaseExecutor } from "./base.js";
|
|
29
29
|
import { PROVIDERS } from "../config/providers.js";
|
|
30
30
|
import { proxyAwareFetch } from "../utils/proxyFetch.js";
|
|
31
|
+
import { SSE_DONE } from "../utils/sseConstants.js";
|
|
32
|
+
import { FETCH_CONNECT_TIMEOUT_MS } from "../config/runtimeConfig.js";
|
|
31
33
|
import {
|
|
32
34
|
QODER_CHAT_URL_ENCODED,
|
|
33
35
|
QODER_MODEL_MAP,
|
|
34
|
-
} from
|
|
36
|
+
} from "../shared/qoder/constants.js";
|
|
35
37
|
import { getQoderModelConfig, resolveQoderModels } from "../services/qoderModels.js";
|
|
36
38
|
|
|
37
39
|
/**
|
|
@@ -124,7 +126,7 @@ function truncate(s, n) {
|
|
|
124
126
|
* Map the OpenAI-style request body into the exact shape Qoder expects.
|
|
125
127
|
*/
|
|
126
128
|
async function buildQoderRequestBody({ model, body, credentials, log, proxyOptions, signal }) {
|
|
127
|
-
const qoderKey = String(model || "").replace(/^
|
|
129
|
+
const qoderKey = String(model || "").replace(/^qoder\//, "");
|
|
128
130
|
|
|
129
131
|
// Fetch model config from dynamic API instead of relying on static QODER_MODEL_MAP.
|
|
130
132
|
// This allows support for new Qoder models (e.g., qmodel_latest) without code changes.
|
|
@@ -240,9 +242,8 @@ function wrapQoderSSE(response, model) {
|
|
|
240
242
|
|
|
241
243
|
const data = trimmed.slice(5).trimStart();
|
|
242
244
|
if (data === "[DONE]") {
|
|
243
|
-
controller.enqueue(encoder.encode(
|
|
245
|
+
controller.enqueue(encoder.encode(SSE_DONE));
|
|
244
246
|
doneEmitted = true;
|
|
245
|
-
try { controller.terminate(); } catch {}
|
|
246
247
|
return;
|
|
247
248
|
}
|
|
248
249
|
|
|
@@ -260,16 +261,14 @@ function wrapQoderSSE(response, model) {
|
|
|
260
261
|
choices: [{ index: 0, delta: { content: `\n[qoder error ${statusVal}: ${truncate(msg, 200)}]` }, finish_reason: "stop" }],
|
|
261
262
|
});
|
|
262
263
|
controller.enqueue(encoder.encode(`data: ${errChunk}\n\n`));
|
|
263
|
-
controller.enqueue(encoder.encode(
|
|
264
|
+
controller.enqueue(encoder.encode(SSE_DONE));
|
|
264
265
|
doneEmitted = true;
|
|
265
|
-
try { controller.terminate(); } catch {}
|
|
266
266
|
return;
|
|
267
267
|
}
|
|
268
268
|
if (!inner) return;
|
|
269
269
|
if (inner === "[DONE]") {
|
|
270
|
-
controller.enqueue(encoder.encode(
|
|
270
|
+
controller.enqueue(encoder.encode(SSE_DONE));
|
|
271
271
|
doneEmitted = true;
|
|
272
|
-
try { controller.terminate(); } catch {}
|
|
273
272
|
return;
|
|
274
273
|
}
|
|
275
274
|
// Inner is an OpenAI-shaped chunk. Strip any embedded newlines so the
|
|
@@ -303,7 +302,7 @@ function wrapQoderSSE(response, model) {
|
|
|
303
302
|
buffer = "";
|
|
304
303
|
}
|
|
305
304
|
if (!doneEmitted) {
|
|
306
|
-
controller.enqueue(encoder.encode(
|
|
305
|
+
controller.enqueue(encoder.encode(SSE_DONE));
|
|
307
306
|
doneEmitted = true;
|
|
308
307
|
}
|
|
309
308
|
},
|
|
@@ -410,15 +409,21 @@ export class QoderExecutor extends BaseExecutor {
|
|
|
410
409
|
...cosyHeaders,
|
|
411
410
|
};
|
|
412
411
|
|
|
412
|
+
// Abort if upstream doesn't return response headers within connect timeout.
|
|
413
|
+
const timeoutMs = this.config?.timeoutMs || FETCH_CONNECT_TIMEOUT_MS;
|
|
414
|
+
const connectCtrl = new AbortController();
|
|
415
|
+
const connectTimer = setTimeout(() => connectCtrl.abort(new Error("fetch connect timeout")), timeoutMs);
|
|
416
|
+
const mergedSignal = signal ? AbortSignal.any([signal, connectCtrl.signal]) : connectCtrl.signal;
|
|
417
|
+
|
|
413
418
|
let response;
|
|
414
419
|
try {
|
|
415
420
|
response = await proxyAwareFetch(
|
|
416
421
|
url,
|
|
417
|
-
{ method: "POST", headers, body: encodedBodyBuf, signal },
|
|
422
|
+
{ method: "POST", headers, body: encodedBodyBuf, signal: mergedSignal },
|
|
418
423
|
proxyOptions,
|
|
419
424
|
);
|
|
420
|
-
}
|
|
421
|
-
|
|
425
|
+
} finally {
|
|
426
|
+
clearTimeout(connectTimer);
|
|
422
427
|
}
|
|
423
428
|
|
|
424
429
|
if (!response.ok) {
|
|
@@ -430,10 +435,15 @@ export class QoderExecutor extends BaseExecutor {
|
|
|
430
435
|
return { response: wrapped, url, headers, transformedBody: payload };
|
|
431
436
|
}
|
|
432
437
|
|
|
433
|
-
//
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
438
|
+
// Qoder device tokens don't refresh through OAuth — the upstream returns
|
|
439
|
+
// 403 for our flow. Surfacing failure via 401-on-chat is enough; the
|
|
440
|
+
// dashboard tells users to re-login when their token expires (~30 days).
|
|
441
|
+
async refreshCredentials() {
|
|
442
|
+
return null;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
needsRefresh() {
|
|
446
|
+
return false;
|
|
437
447
|
}
|
|
438
448
|
}
|
|
439
449
|
|
|
@@ -1,11 +1,33 @@
|
|
|
1
1
|
import { BaseExecutor } from "./base.js";
|
|
2
2
|
import { PROVIDERS } from "../config/providers.js";
|
|
3
|
-
import { parseVertexSaJson, refreshVertexToken } from "../services/tokenRefresh.js";
|
|
3
|
+
import { parseVertexSaJson, refreshVertexToken, refreshGoogleToken } from "../services/tokenRefresh.js";
|
|
4
4
|
import { proxyAwareFetch } from "../utils/proxyFetch.js";
|
|
5
5
|
|
|
6
6
|
// Cache project IDs resolved from raw API keys { apiKey → projectId }
|
|
7
7
|
const projectIdCache = new Map();
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Parse Google ADC user credential JSON from apiKey string.
|
|
11
|
+
* This is the format produced by `gcloud auth application-default login`.
|
|
12
|
+
*/
|
|
13
|
+
function parseVertexAdcJson(apiKey) {
|
|
14
|
+
if (typeof apiKey !== "string") return null;
|
|
15
|
+
try {
|
|
16
|
+
const parsed = JSON.parse(apiKey);
|
|
17
|
+
if (
|
|
18
|
+
parsed.type === "authorized_user" &&
|
|
19
|
+
parsed.client_id &&
|
|
20
|
+
parsed.client_secret &&
|
|
21
|
+
parsed.refresh_token
|
|
22
|
+
) {
|
|
23
|
+
return parsed;
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
} catch {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
9
31
|
/**
|
|
10
32
|
* Resolve GCP project ID from a raw Vertex API key.
|
|
11
33
|
* Sends a dummy 404 request and parses "projects/{id}" from the error message.
|
|
@@ -43,8 +65,13 @@ export class VertexExecutor extends BaseExecutor {
|
|
|
43
65
|
|
|
44
66
|
buildUrl(model, stream, urlIndex = 0, credentials = null) {
|
|
45
67
|
const saJson = parseVertexSaJson(credentials?.apiKey);
|
|
46
|
-
const
|
|
47
|
-
const
|
|
68
|
+
const adcJson = parseVertexAdcJson(credentials?.apiKey);
|
|
69
|
+
const usesOAuth = !!saJson || !!adcJson || !!credentials?.accessToken;
|
|
70
|
+
const rawKey = !usesOAuth ? credentials?.apiKey : null;
|
|
71
|
+
const projectId =
|
|
72
|
+
saJson?.project_id ||
|
|
73
|
+
adcJson?.quota_project_id ||
|
|
74
|
+
credentials?.providerSpecificData?.projectId;
|
|
48
75
|
|
|
49
76
|
if (this.provider === "vertex-partner") {
|
|
50
77
|
// Partner models require project_id in path regardless of auth method
|
|
@@ -56,8 +83,14 @@ export class VertexExecutor extends BaseExecutor {
|
|
|
56
83
|
// Gemini on Vertex
|
|
57
84
|
const action = stream ? "streamGenerateContent" : "generateContent";
|
|
58
85
|
|
|
59
|
-
if (
|
|
60
|
-
// SA JSON
|
|
86
|
+
if (usesOAuth) {
|
|
87
|
+
// SA JSON / ADC / pre-set accessToken: must use project-scoped path to avoid RESOURCE_PROJECT_INVALID
|
|
88
|
+
if (!projectId) {
|
|
89
|
+
throw new Error(
|
|
90
|
+
"Vertex OAuth/ADC requires a project_id. " +
|
|
91
|
+
"Add quota_project_id to your ADC JSON or set providerSpecificData.projectId."
|
|
92
|
+
);
|
|
93
|
+
}
|
|
61
94
|
const location = credentials?.providerSpecificData?.location || "us-central1";
|
|
62
95
|
let url = `https://aiplatform.googleapis.com/v1/projects/${projectId}/locations/${location}/publishers/google/models/${model}:${action}`;
|
|
63
96
|
if (stream) url += "?alt=sse";
|
|
@@ -97,16 +130,29 @@ export class VertexExecutor extends BaseExecutor {
|
|
|
97
130
|
|
|
98
131
|
async execute({ model, body, stream, credentials, signal, log, proxyOptions = null }) {
|
|
99
132
|
const saJson = parseVertexSaJson(credentials?.apiKey);
|
|
133
|
+
const adcJson = parseVertexAdcJson(credentials?.apiKey);
|
|
100
134
|
|
|
101
|
-
// SA JSON flow: mint Bearer token (cached)
|
|
135
|
+
// SA JSON flow: mint Bearer token via JWT assertion (cached)
|
|
102
136
|
if (saJson) {
|
|
103
137
|
const result = await refreshVertexToken(saJson, log);
|
|
104
138
|
if (!result?.accessToken) throw new Error("Vertex: failed to mint access token from Service Account JSON");
|
|
105
139
|
credentials.accessToken = result.accessToken;
|
|
106
140
|
}
|
|
107
141
|
|
|
142
|
+
// ADC user credential flow: refresh Bearer token via Google OAuth2 token endpoint
|
|
143
|
+
if (adcJson) {
|
|
144
|
+
const result = await refreshGoogleToken(
|
|
145
|
+
adcJson.refresh_token,
|
|
146
|
+
adcJson.client_id,
|
|
147
|
+
adcJson.client_secret,
|
|
148
|
+
log
|
|
149
|
+
);
|
|
150
|
+
if (!result?.accessToken) throw new Error("Vertex: failed to refresh access token from ADC JSON (authorized_user)");
|
|
151
|
+
credentials.accessToken = result.accessToken;
|
|
152
|
+
}
|
|
153
|
+
|
|
108
154
|
// vertex-partner with raw key: auto-resolve project_id if not provided
|
|
109
|
-
if (this.provider === "vertex-partner" && !saJson && !credentials?.providerSpecificData?.projectId) {
|
|
155
|
+
if (this.provider === "vertex-partner" && !saJson && !adcJson && !credentials?.providerSpecificData?.projectId) {
|
|
110
156
|
const projectId = await resolveProjectId(credentials.apiKey);
|
|
111
157
|
if (!projectId) throw new Error("Vertex: could not resolve project_id from API key. Please add it manually in provider settings.");
|
|
112
158
|
log?.debug?.("VERTEX", `Resolved project_id: ${projectId}`);
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import { DefaultExecutor } from "./default.js";
|
|
2
2
|
import { resolveXiaomiTokenplanBaseUrl } from "../config/providers.js";
|
|
3
|
-
import { getModelTargetFormat } from "../config/providerModels.js";
|
|
4
|
-
import { FORMATS } from "../translator/formats.js";
|
|
3
|
+
// import { getModelTargetFormat } from "../config/providerModels.js";
|
|
4
|
+
// import { FORMATS } from "../translator/formats.js";
|
|
5
5
|
|
|
6
6
|
export class XiaomiTokenplanExecutor extends DefaultExecutor {
|
|
7
7
|
constructor() {
|
|
8
8
|
super("xiaomi-tokenplan");
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
//
|
|
11
|
+
// Token Plan keys are region-specific. Route per sourceFormat-matched transport:
|
|
12
|
+
// claude → Anthropic /anthropic/v1/messages, openai → /chat/completions.
|
|
12
13
|
buildUrl(model, stream, urlIndex = 0, credentials = null) {
|
|
13
14
|
const baseUrl = resolveXiaomiTokenplanBaseUrl(credentials);
|
|
14
|
-
if (
|
|
15
|
-
return `${baseUrl.replace(/\/v1\/?$/, "/anthropic/v1
|
|
15
|
+
if (credentials?.runtimeTransport?.format === "claude") {
|
|
16
|
+
return `${baseUrl.replace(/\/v1\/?$/, "")}/anthropic/v1/messages`;
|
|
16
17
|
}
|
|
17
18
|
return `${baseUrl}/chat/completions`;
|
|
18
19
|
}
|