Browse Source

feat(openai): Add Config Option to Overwrite OpenAI's API Base (#3066)

* feat(openai): Add Config Option to Overwrite OpenAI's API Base

* feat(openai): Add option to use custom base URL for OpenAI native API
gongzhongqiang 10 months ago
parent
commit
8c428b5b63

+ 2 - 0
evals/packages/types/src/roo-code.ts

@@ -358,6 +358,7 @@ export const providerSettingsSchema = z.object({
 	googleGeminiBaseUrl: z.string().optional(),
 	// OpenAI Native
 	openAiNativeApiKey: z.string().optional(),
+	openAiNativeBaseUrl: z.string().optional(),
 	// XAI
 	xaiApiKey: z.string().optional(),
 	// Mistral
@@ -445,6 +446,7 @@ const providerSettingsRecord: ProviderSettingsRecord = {
 	googleGeminiBaseUrl: undefined,
 	// OpenAI Native
 	openAiNativeApiKey: undefined,
+	openAiNativeBaseUrl: undefined,
 	// Mistral
 	mistralApiKey: undefined,
 	mistralCodestralUrl: undefined,

+ 1 - 1
src/api/providers/openai-native.ts

@@ -29,7 +29,7 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio
 		super()
 		this.options = options
 		const apiKey = this.options.openAiNativeApiKey ?? "not-provided"
-		this.client = new OpenAI({ apiKey })
+		this.client = new OpenAI({ baseURL: this.options.openAiNativeBaseUrl, apiKey })
 	}
 
 	override async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {

+ 1 - 0
src/exports/roo-code.d.ts

@@ -105,6 +105,7 @@ type ProviderSettings = {
 	geminiApiKey?: string | undefined
 	googleGeminiBaseUrl?: string | undefined
 	openAiNativeApiKey?: string | undefined
+	openAiNativeBaseUrl?: string | undefined
 	mistralApiKey?: string | undefined
 	mistralCodestralUrl?: string | undefined
 	deepSeekBaseUrl?: string | undefined

+ 1 - 0
src/exports/types.ts

@@ -106,6 +106,7 @@ type ProviderSettings = {
 	geminiApiKey?: string | undefined
 	googleGeminiBaseUrl?: string | undefined
 	openAiNativeApiKey?: string | undefined
+	openAiNativeBaseUrl?: string | undefined
 	mistralApiKey?: string | undefined
 	mistralCodestralUrl?: string | undefined
 	deepSeekBaseUrl?: string | undefined

+ 2 - 0
src/schemas/index.ts

@@ -401,6 +401,7 @@ export const providerSettingsSchema = z.object({
 	googleGeminiBaseUrl: z.string().optional(),
 	// OpenAI Native
 	openAiNativeApiKey: z.string().optional(),
+	openAiNativeBaseUrl: z.string().optional(),
 	// Mistral
 	mistralApiKey: z.string().optional(),
 	mistralCodestralUrl: z.string().optional(),
@@ -492,6 +493,7 @@ const providerSettingsRecord: ProviderSettingsRecord = {
 	googleGeminiBaseUrl: undefined,
 	// OpenAI Native
 	openAiNativeApiKey: undefined,
+	openAiNativeBaseUrl: undefined,
 	// Mistral
 	mistralApiKey: undefined,
 	mistralCodestralUrl: undefined,

+ 25 - 0
webview-ui/src/components/settings/ApiOptions.tsx

@@ -75,6 +75,9 @@ const ApiOptions = ({
 	const [openAiModels, setOpenAiModels] = useState<Record<string, ModelInfo> | null>(null)
 
 	const [anthropicBaseUrlSelected, setAnthropicBaseUrlSelected] = useState(!!apiConfiguration?.anthropicBaseUrl)
+	const [openAiNativeBaseUrlSelected, setOpenAiNativeBaseUrlSelected] = useState(
+		!!apiConfiguration?.openAiNativeBaseUrl,
+	)
 	const [azureApiVersionSelected, setAzureApiVersionSelected] = useState(!!apiConfiguration?.azureApiVersion)
 	const [openRouterBaseUrlSelected, setOpenRouterBaseUrlSelected] = useState(!!apiConfiguration?.openRouterBaseUrl)
 	const [openAiHostHeaderSelected, setOpenAiHostHeaderSelected] = useState(!!apiConfiguration?.openAiHostHeader)
@@ -490,6 +493,28 @@ const ApiOptions = ({
 
 			{selectedProvider === "openai-native" && (
 				<>
+					<Checkbox
+						checked={openAiNativeBaseUrlSelected}
+						onChange={(checked: boolean) => {
+							setOpenAiNativeBaseUrlSelected(checked)
+
+							if (!checked) {
+								setApiConfigurationField("openAiNativeBaseUrl", "")
+							}
+						}}>
+						{t("settings:providers.useCustomBaseUrl")}
+					</Checkbox>
+					{openAiNativeBaseUrlSelected && (
+						<>
+							<VSCodeTextField
+								value={apiConfiguration?.openAiNativeBaseUrl || ""}
+								type="url"
+								onInput={handleInputChange("openAiNativeBaseUrl")}
+								placeholder="https://api.openai.com/v1"
+								className="w-full mt-1"
+							/>
+						</>
+					)}
 					<VSCodeTextField
 						value={apiConfiguration?.openAiNativeApiKey || ""}
 						type="password"