mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
Add the option to use a custom Host header for openai-compatible (#2399)
This commit is contained in:
parent
9f724bd360
commit
b01615f122
22 changed files with 112 additions and 8 deletions
|
|
@ -26,9 +26,11 @@ demo.gif
|
|||
.prettierignore
|
||||
.clinerules*
|
||||
.roomodes
|
||||
.roo/**
|
||||
cline_docs/**
|
||||
coverage/**
|
||||
locales/**
|
||||
benchmark/**
|
||||
|
||||
# Ignore all webview-ui files except the build directory (https://github.com/microsoft/vscode-webview-ui-toolkit-samples/blob/main/frameworks/hello-world-react-cra/.vscodeignore)
|
||||
webview-ui/src/**
|
||||
|
|
|
|||
|
|
@ -55,10 +55,20 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
|
|||
baseURL,
|
||||
apiKey,
|
||||
apiVersion: this.options.azureApiVersion || azureOpenAiDefaultApiVersion,
|
||||
defaultHeaders,
|
||||
defaultHeaders: {
|
||||
...defaultHeaders,
|
||||
...(this.options.openAiHostHeader ? { Host: this.options.openAiHostHeader } : {}),
|
||||
},
|
||||
})
|
||||
} else {
|
||||
this.client = new OpenAI({ baseURL, apiKey, defaultHeaders })
|
||||
this.client = new OpenAI({
|
||||
baseURL,
|
||||
apiKey,
|
||||
defaultHeaders: {
|
||||
...defaultHeaders,
|
||||
...(this.options.openAiHostHeader ? { Host: this.options.openAiHostHeader } : {}),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -67,6 +77,7 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
|
|||
const modelUrl = this.options.openAiBaseUrl ?? ""
|
||||
const modelId = this.options.openAiModelId ?? ""
|
||||
const enabledR1Format = this.options.openAiR1FormatEnabled ?? false
|
||||
const enabledLegacyFormat = this.options.openAiLegacyFormat ?? false
|
||||
const isAzureAiInference = this._isAzureAiInference(modelUrl)
|
||||
const urlHost = this._getUrlHost(modelUrl)
|
||||
const deepseekReasoner = modelId.includes("deepseek-reasoner") || enabledR1Format
|
||||
|
|
@ -85,7 +96,7 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
|
|||
let convertedMessages
|
||||
if (deepseekReasoner) {
|
||||
convertedMessages = convertToR1Format([{ role: "user", content: systemPrompt }, ...messages])
|
||||
} else if (ark) {
|
||||
} else if (ark || enabledLegacyFormat) {
|
||||
convertedMessages = [systemMessage, ...convertToSimpleMessages(messages)]
|
||||
} else {
|
||||
if (modelInfo.supportsPromptCache) {
|
||||
|
|
@ -190,7 +201,9 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
|
|||
model: modelId,
|
||||
messages: deepseekReasoner
|
||||
? convertToR1Format([{ role: "user", content: systemPrompt }, ...messages])
|
||||
: [systemMessage, ...convertToOpenAiMessages(messages)],
|
||||
: enabledLegacyFormat
|
||||
? [systemMessage, ...convertToSimpleMessages(messages)]
|
||||
: [systemMessage, ...convertToOpenAiMessages(messages)],
|
||||
}
|
||||
|
||||
const response = await this.client.chat.completions.create(
|
||||
|
|
@ -330,7 +343,7 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
|
|||
}
|
||||
}
|
||||
|
||||
export async function getOpenAiModels(baseUrl?: string, apiKey?: string) {
|
||||
export async function getOpenAiModels(baseUrl?: string, apiKey?: string, hostHeader?: string) {
|
||||
try {
|
||||
if (!baseUrl) {
|
||||
return []
|
||||
|
|
@ -341,9 +354,18 @@ export async function getOpenAiModels(baseUrl?: string, apiKey?: string) {
|
|||
}
|
||||
|
||||
const config: Record<string, any> = {}
|
||||
const headers: Record<string, string> = {}
|
||||
|
||||
if (apiKey) {
|
||||
config["headers"] = { Authorization: `Bearer ${apiKey}` }
|
||||
headers["Authorization"] = `Bearer ${apiKey}`
|
||||
}
|
||||
|
||||
if (hostHeader) {
|
||||
headers["Host"] = hostHeader
|
||||
}
|
||||
|
||||
if (Object.keys(headers).length > 0) {
|
||||
config["headers"] = headers
|
||||
}
|
||||
|
||||
const response = await axios.get(`${baseUrl}/models`, config)
|
||||
|
|
|
|||
|
|
@ -423,7 +423,11 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We
|
|||
break
|
||||
case "refreshOpenAiModels":
|
||||
if (message?.values?.baseUrl && message?.values?.apiKey) {
|
||||
const openAiModels = await getOpenAiModels(message?.values?.baseUrl, message?.values?.apiKey)
|
||||
const openAiModels = await getOpenAiModels(
|
||||
message?.values?.baseUrl,
|
||||
message?.values?.apiKey,
|
||||
message?.values?.hostHeader,
|
||||
)
|
||||
provider.postMessageToWebview({ type: "openAiModels", openAiModels })
|
||||
}
|
||||
|
||||
|
|
|
|||
2
src/exports/roo-code.d.ts
vendored
2
src/exports/roo-code.d.ts
vendored
|
|
@ -86,6 +86,8 @@ type ProviderSettings = {
|
|||
vertexRegion?: string | undefined
|
||||
openAiBaseUrl?: string | undefined
|
||||
openAiApiKey?: string | undefined
|
||||
openAiHostHeader?: string | undefined
|
||||
openAiLegacyFormat?: boolean | undefined
|
||||
openAiR1FormatEnabled?: boolean | undefined
|
||||
openAiModelId?: string | undefined
|
||||
openAiCustomModelInfo?:
|
||||
|
|
|
|||
|
|
@ -87,6 +87,8 @@ type ProviderSettings = {
|
|||
vertexRegion?: string | undefined
|
||||
openAiBaseUrl?: string | undefined
|
||||
openAiApiKey?: string | undefined
|
||||
openAiHostHeader?: string | undefined
|
||||
openAiLegacyFormat?: boolean | undefined
|
||||
openAiR1FormatEnabled?: boolean | undefined
|
||||
openAiModelId?: string | undefined
|
||||
openAiCustomModelInfo?:
|
||||
|
|
|
|||
|
|
@ -338,6 +338,8 @@ export const providerSettingsSchema = z.object({
|
|||
// OpenAI
|
||||
openAiBaseUrl: z.string().optional(),
|
||||
openAiApiKey: z.string().optional(),
|
||||
openAiHostHeader: z.string().optional(),
|
||||
openAiLegacyFormat: z.boolean().optional(),
|
||||
openAiR1FormatEnabled: z.boolean().optional(),
|
||||
openAiModelId: z.string().optional(),
|
||||
openAiCustomModelInfo: modelInfoSchema.nullish(),
|
||||
|
|
@ -431,6 +433,8 @@ const providerSettingsRecord: ProviderSettingsRecord = {
|
|||
// OpenAI
|
||||
openAiBaseUrl: undefined,
|
||||
openAiApiKey: undefined,
|
||||
openAiHostHeader: undefined,
|
||||
openAiLegacyFormat: undefined,
|
||||
openAiR1FormatEnabled: undefined,
|
||||
openAiModelId: undefined,
|
||||
openAiCustomModelInfo: undefined,
|
||||
|
|
|
|||
|
|
@ -103,6 +103,8 @@ const ApiOptions = ({
|
|||
const [anthropicBaseUrlSelected, setAnthropicBaseUrlSelected] = useState(!!apiConfiguration?.anthropicBaseUrl)
|
||||
const [azureApiVersionSelected, setAzureApiVersionSelected] = useState(!!apiConfiguration?.azureApiVersion)
|
||||
const [openRouterBaseUrlSelected, setOpenRouterBaseUrlSelected] = useState(!!apiConfiguration?.openRouterBaseUrl)
|
||||
const [openAiHostHeaderSelected, setOpenAiHostHeaderSelected] = useState(!!apiConfiguration?.openAiHostHeader)
|
||||
const [openAiLegacyFormatSelected, setOpenAiLegacyFormatSelected] = useState(!!apiConfiguration?.openAiLegacyFormat)
|
||||
const [googleGeminiBaseUrlSelected, setGoogleGeminiBaseUrlSelected] = useState(
|
||||
!!apiConfiguration?.googleGeminiBaseUrl,
|
||||
)
|
||||
|
|
@ -145,7 +147,11 @@ const ApiOptions = ({
|
|||
} else if (selectedProvider === "openai") {
|
||||
vscode.postMessage({
|
||||
type: "refreshOpenAiModels",
|
||||
values: { baseUrl: apiConfiguration?.openAiBaseUrl, apiKey: apiConfiguration?.openAiApiKey },
|
||||
values: {
|
||||
baseUrl: apiConfiguration?.openAiBaseUrl,
|
||||
apiKey: apiConfiguration?.openAiApiKey,
|
||||
hostHeader: apiConfiguration?.openAiHostHeader,
|
||||
},
|
||||
})
|
||||
} else if (selectedProvider === "ollama") {
|
||||
vscode.postMessage({ type: "requestOllamaModels", text: apiConfiguration?.ollamaBaseUrl })
|
||||
|
|
@ -779,6 +785,16 @@ const ApiOptions = ({
|
|||
onChange={handleInputChange("openAiR1FormatEnabled", noTransform)}
|
||||
openAiR1FormatEnabled={apiConfiguration?.openAiR1FormatEnabled ?? false}
|
||||
/>
|
||||
<div>
|
||||
<Checkbox
|
||||
checked={openAiLegacyFormatSelected}
|
||||
onChange={(checked: boolean) => {
|
||||
setOpenAiLegacyFormatSelected(checked)
|
||||
setApiConfigurationField("openAiLegacyFormat", checked)
|
||||
}}>
|
||||
{t("settings:providers.useLegacyFormat")}
|
||||
</Checkbox>
|
||||
</div>
|
||||
<Checkbox
|
||||
checked={apiConfiguration?.openAiStreamingEnabled ?? true}
|
||||
onChange={handleInputChange("openAiStreamingEnabled", noTransform)}>
|
||||
|
|
@ -811,6 +827,28 @@ const ApiOptions = ({
|
|||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Checkbox
|
||||
checked={openAiHostHeaderSelected}
|
||||
onChange={(checked: boolean) => {
|
||||
setOpenAiHostHeaderSelected(checked)
|
||||
|
||||
if (!checked) {
|
||||
setApiConfigurationField("openAiHostHeader", "")
|
||||
}
|
||||
}}>
|
||||
{t("settings:providers.useHostHeader")}
|
||||
</Checkbox>
|
||||
{openAiHostHeaderSelected && (
|
||||
<VSCodeTextField
|
||||
value={apiConfiguration?.openAiHostHeader || ""}
|
||||
onInput={handleInputChange("openAiHostHeader")}
|
||||
placeholder="custom-api-hostname.example.com"
|
||||
className="w-full mt-1"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-3">
|
||||
<div className="text-sm text-vscode-descriptionForeground">
|
||||
{t("settings:providers.customModel.capabilities")}
|
||||
|
|
|
|||
|
|
@ -105,6 +105,8 @@
|
|||
"awsCustomArnDesc": "Assegureu-vos que la regió a l'ARN coincideix amb la regió d'AWS seleccionada anteriorment.",
|
||||
"apiKeyStorageNotice": "Les claus API s'emmagatzemen de forma segura a l'Emmagatzematge Secret de VSCode",
|
||||
"useCustomBaseUrl": "Utilitzar URL base personalitzada",
|
||||
"useHostHeader": "Utilitzar capçalera Host personalitzada",
|
||||
"useLegacyFormat": "Utilitzar el format d'API OpenAI antic",
|
||||
"openRouterTransformsText": "Comprimir prompts i cadenes de missatges a la mida del context (<a>Transformacions d'OpenRouter</a>)",
|
||||
"model": "Model",
|
||||
"getOpenRouterApiKey": "Obtenir clau API d'OpenRouter",
|
||||
|
|
|
|||
|
|
@ -109,6 +109,8 @@
|
|||
"glamaApiKey": "Glama API-Schlüssel",
|
||||
"getGlamaApiKey": "Glama API-Schlüssel erhalten",
|
||||
"useCustomBaseUrl": "Benutzerdefinierte Basis-URL verwenden",
|
||||
"useHostHeader": "Benutzerdefinierten Host-Header verwenden",
|
||||
"useLegacyFormat": "Altes OpenAI API-Format verwenden",
|
||||
"requestyApiKey": "Requesty API-Schlüssel",
|
||||
"getRequestyApiKey": "Requesty API-Schlüssel erhalten",
|
||||
"openRouterTransformsText": "Prompts und Nachrichtenketten auf Kontextgröße komprimieren (<a>OpenRouter Transformationen</a>)",
|
||||
|
|
|
|||
|
|
@ -109,6 +109,8 @@
|
|||
"glamaApiKey": "Glama API Key",
|
||||
"getGlamaApiKey": "Get Glama API Key",
|
||||
"useCustomBaseUrl": "Use custom base URL",
|
||||
"useHostHeader": "Use custom Host header",
|
||||
"useLegacyFormat": "Use legacy OpenAI API format",
|
||||
"requestyApiKey": "Requesty API Key",
|
||||
"getRequestyApiKey": "Get Requesty API Key",
|
||||
"openRouterTransformsText": "Compress prompts and message chains to the context size (<a>OpenRouter Transforms</a>)",
|
||||
|
|
|
|||
|
|
@ -109,6 +109,8 @@
|
|||
"glamaApiKey": "Clave API de Glama",
|
||||
"getGlamaApiKey": "Obtener clave API de Glama",
|
||||
"useCustomBaseUrl": "Usar URL base personalizada",
|
||||
"useHostHeader": "Usar encabezado Host personalizado",
|
||||
"useLegacyFormat": "Usar formato API de OpenAI heredado",
|
||||
"requestyApiKey": "Clave API de Requesty",
|
||||
"getRequestyApiKey": "Obtener clave API de Requesty",
|
||||
"openRouterTransformsText": "Comprimir prompts y cadenas de mensajes al tamaño del contexto (<a>Transformaciones de OpenRouter</a>)",
|
||||
|
|
|
|||
|
|
@ -109,6 +109,8 @@
|
|||
"glamaApiKey": "Clé API Glama",
|
||||
"getGlamaApiKey": "Obtenir la clé API Glama",
|
||||
"useCustomBaseUrl": "Utiliser une URL de base personnalisée",
|
||||
"useHostHeader": "Utiliser un en-tête Host personnalisé",
|
||||
"useLegacyFormat": "Utiliser le format API OpenAI hérité",
|
||||
"requestyApiKey": "Clé API Requesty",
|
||||
"getRequestyApiKey": "Obtenir la clé API Requesty",
|
||||
"openRouterTransformsText": "Compresser les prompts et chaînes de messages à la taille du contexte (<a>Transformations OpenRouter</a>)",
|
||||
|
|
|
|||
|
|
@ -109,6 +109,8 @@
|
|||
"glamaApiKey": "Glama API कुंजी",
|
||||
"getGlamaApiKey": "Glama API कुंजी प्राप्त करें",
|
||||
"useCustomBaseUrl": "कस्टम बेस URL का उपयोग करें",
|
||||
"useHostHeader": "कस्टम होस्ट हेडर का उपयोग करें",
|
||||
"useLegacyFormat": "पुराने OpenAI API प्रारूप का उपयोग करें",
|
||||
"requestyApiKey": "Requesty API कुंजी",
|
||||
"getRequestyApiKey": "Requesty API कुंजी प्राप्त करें",
|
||||
"openRouterTransformsText": "संदर्भ आकार के लिए प्रॉम्प्ट और संदेश श्रृंखलाओं को संपीड़ित करें (<a>OpenRouter ट्रांसफॉर्म</a>)",
|
||||
|
|
|
|||
|
|
@ -109,6 +109,8 @@
|
|||
"glamaApiKey": "Chiave API Glama",
|
||||
"getGlamaApiKey": "Ottieni chiave API Glama",
|
||||
"useCustomBaseUrl": "Usa URL base personalizzato",
|
||||
"useHostHeader": "Usa intestazione Host personalizzata",
|
||||
"useLegacyFormat": "Usa formato API OpenAI legacy",
|
||||
"requestyApiKey": "Chiave API Requesty",
|
||||
"getRequestyApiKey": "Ottieni chiave API Requesty",
|
||||
"openRouterTransformsText": "Comprimi prompt e catene di messaggi alla dimensione del contesto (<a>Trasformazioni OpenRouter</a>)",
|
||||
|
|
|
|||
|
|
@ -109,6 +109,8 @@
|
|||
"glamaApiKey": "Glama APIキー",
|
||||
"getGlamaApiKey": "Glama APIキーを取得",
|
||||
"useCustomBaseUrl": "カスタムベースURLを使用",
|
||||
"useHostHeader": "カスタムHostヘッダーを使用",
|
||||
"useLegacyFormat": "レガシーOpenAI API形式を使用",
|
||||
"requestyApiKey": "Requesty APIキー",
|
||||
"getRequestyApiKey": "Requesty APIキーを取得",
|
||||
"openRouterTransformsText": "プロンプトとメッセージチェーンをコンテキストサイズに圧縮 (<a>OpenRouter Transforms</a>)",
|
||||
|
|
|
|||
|
|
@ -109,6 +109,8 @@
|
|||
"glamaApiKey": "Glama API 키",
|
||||
"getGlamaApiKey": "Glama API 키 받기",
|
||||
"useCustomBaseUrl": "사용자 정의 기본 URL 사용",
|
||||
"useHostHeader": "사용자 정의 Host 헤더 사용",
|
||||
"useLegacyFormat": "레거시 OpenAI API 형식 사용",
|
||||
"requestyApiKey": "Requesty API 키",
|
||||
"getRequestyApiKey": "Requesty API 키 받기",
|
||||
"openRouterTransformsText": "프롬프트와 메시지 체인을 컨텍스트 크기로 압축 (<a>OpenRouter Transforms</a>)",
|
||||
|
|
|
|||
|
|
@ -109,6 +109,8 @@
|
|||
"glamaApiKey": "Klucz API Glama",
|
||||
"getGlamaApiKey": "Uzyskaj klucz API Glama",
|
||||
"useCustomBaseUrl": "Użyj niestandardowego URL bazowego",
|
||||
"useHostHeader": "Użyj niestandardowego nagłówka Host",
|
||||
"useLegacyFormat": "Użyj starszego formatu API OpenAI",
|
||||
"requestyApiKey": "Klucz API Requesty",
|
||||
"getRequestyApiKey": "Uzyskaj klucz API Requesty",
|
||||
"openRouterTransformsText": "Kompresuj podpowiedzi i łańcuchy wiadomości do rozmiaru kontekstu (<a>Transformacje OpenRouter</a>)",
|
||||
|
|
|
|||
|
|
@ -109,6 +109,8 @@
|
|||
"glamaApiKey": "Chave de API Glama",
|
||||
"getGlamaApiKey": "Obter chave de API Glama",
|
||||
"useCustomBaseUrl": "Usar URL base personalizado",
|
||||
"useHostHeader": "Usar cabeçalho Host personalizado",
|
||||
"useLegacyFormat": "Usar formato de API OpenAI legado",
|
||||
"requestyApiKey": "Chave de API Requesty",
|
||||
"getRequestyApiKey": "Obter chave de API Requesty",
|
||||
"openRouterTransformsText": "Comprimir prompts e cadeias de mensagens para o tamanho do contexto (<a>Transformações OpenRouter</a>)",
|
||||
|
|
|
|||
|
|
@ -109,6 +109,8 @@
|
|||
"glamaApiKey": "Glama API Anahtarı",
|
||||
"getGlamaApiKey": "Glama API Anahtarı Al",
|
||||
"useCustomBaseUrl": "Özel temel URL kullan",
|
||||
"useHostHeader": "Özel Host başlığı kullan",
|
||||
"useLegacyFormat": "Eski OpenAI API formatını kullan",
|
||||
"requestyApiKey": "Requesty API Anahtarı",
|
||||
"getRequestyApiKey": "Requesty API Anahtarı Al",
|
||||
"openRouterTransformsText": "İstem ve mesaj zincirlerini bağlam boyutuna sıkıştır (<a>OpenRouter Dönüşümleri</a>)",
|
||||
|
|
|
|||
|
|
@ -109,6 +109,8 @@
|
|||
"glamaApiKey": "Khóa API Glama",
|
||||
"getGlamaApiKey": "Lấy khóa API Glama",
|
||||
"useCustomBaseUrl": "Sử dụng URL cơ sở tùy chỉnh",
|
||||
"useHostHeader": "Sử dụng tiêu đề Host tùy chỉnh",
|
||||
"useLegacyFormat": "Sử dụng định dạng API OpenAI cũ",
|
||||
"requestyApiKey": "Khóa API Requesty",
|
||||
"getRequestyApiKey": "Lấy khóa API Requesty",
|
||||
"anthropicApiKey": "Khóa API Anthropic",
|
||||
|
|
|
|||
|
|
@ -107,6 +107,8 @@
|
|||
"getOpenRouterApiKey": "获取 OpenRouter API 密钥",
|
||||
"apiKeyStorageNotice": "API 密钥安全存储在 VSCode 的密钥存储中",
|
||||
"useCustomBaseUrl": "使用自定义基础 URL",
|
||||
"useHostHeader": "使用自定义 Host 标头",
|
||||
"useLegacyFormat": "使用传统 OpenAI API 格式",
|
||||
"glamaApiKey": "Glama API 密钥",
|
||||
"getGlamaApiKey": "获取 Glama API 密钥",
|
||||
"requestyApiKey": "Requesty API 密钥",
|
||||
|
|
|
|||
|
|
@ -109,6 +109,8 @@
|
|||
"glamaApiKey": "Glama API 金鑰",
|
||||
"getGlamaApiKey": "取得 Glama API 金鑰",
|
||||
"useCustomBaseUrl": "使用自訂基礎 URL",
|
||||
"useHostHeader": "使用自訂 Host 標頭",
|
||||
"useLegacyFormat": "使用舊版 OpenAI API 格式",
|
||||
"requestyApiKey": "Requesty API 金鑰",
|
||||
"getRequestyApiKey": "取得 Requesty API 金鑰",
|
||||
"openRouterTransformsText": "將提示和訊息鏈壓縮到上下文大小 (<a>OpenRouter 轉換</a>)",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue