mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-20 12:21:13 -05:00
Add OpenAI provider
This commit is contained in:
@@ -7,6 +7,7 @@ import { VertexHandler } from "./vertex"
|
|||||||
import { OpenAiHandler } from "./openai"
|
import { OpenAiHandler } from "./openai"
|
||||||
import { OllamaHandler } from "./ollama"
|
import { OllamaHandler } from "./ollama"
|
||||||
import { GeminiHandler } from "./gemini"
|
import { GeminiHandler } from "./gemini"
|
||||||
|
import { OpenAiNativeHandler } from "./openai-native"
|
||||||
|
|
||||||
export interface ApiHandlerMessageResponse {
|
export interface ApiHandlerMessageResponse {
|
||||||
message: Anthropic.Messages.Message
|
message: Anthropic.Messages.Message
|
||||||
@@ -40,6 +41,8 @@ export function buildApiHandler(configuration: ApiConfiguration): ApiHandler {
|
|||||||
return new OllamaHandler(options)
|
return new OllamaHandler(options)
|
||||||
case "gemini":
|
case "gemini":
|
||||||
return new GeminiHandler(options)
|
return new GeminiHandler(options)
|
||||||
|
case "openai-native":
|
||||||
|
return new OpenAiNativeHandler(options)
|
||||||
default:
|
default:
|
||||||
return new AnthropicHandler(options)
|
return new AnthropicHandler(options)
|
||||||
}
|
}
|
||||||
|
|||||||
65
src/api/openai-native.ts
Normal file
65
src/api/openai-native.ts
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import { Anthropic } from "@anthropic-ai/sdk"
|
||||||
|
import OpenAI from "openai"
|
||||||
|
import { ApiHandler, ApiHandlerMessageResponse } from "."
|
||||||
|
import {
|
||||||
|
ApiHandlerOptions,
|
||||||
|
ModelInfo,
|
||||||
|
openAiNativeDefaultModelId,
|
||||||
|
OpenAiNativeModelId,
|
||||||
|
openAiNativeModels,
|
||||||
|
} from "../shared/api"
|
||||||
|
import { convertToAnthropicMessage, convertToOpenAiMessages } from "../utils/openai-format"
|
||||||
|
|
||||||
|
export class OpenAiNativeHandler implements ApiHandler {
|
||||||
|
private options: ApiHandlerOptions
|
||||||
|
private client: OpenAI
|
||||||
|
|
||||||
|
constructor(options: ApiHandlerOptions) {
|
||||||
|
this.options = options
|
||||||
|
this.client = new OpenAI({
|
||||||
|
apiKey: this.options.openAiNativeApiKey,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async createMessage(
|
||||||
|
systemPrompt: string,
|
||||||
|
messages: Anthropic.Messages.MessageParam[],
|
||||||
|
tools: Anthropic.Messages.Tool[]
|
||||||
|
): Promise<ApiHandlerMessageResponse> {
|
||||||
|
const openAiMessages: OpenAI.Chat.ChatCompletionMessageParam[] = [
|
||||||
|
{ role: "system", content: systemPrompt },
|
||||||
|
...convertToOpenAiMessages(messages),
|
||||||
|
]
|
||||||
|
const openAiTools: OpenAI.Chat.ChatCompletionTool[] = tools.map((tool) => ({
|
||||||
|
type: "function",
|
||||||
|
function: {
|
||||||
|
name: tool.name,
|
||||||
|
description: tool.description,
|
||||||
|
parameters: tool.input_schema,
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
const createParams: OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming = {
|
||||||
|
model: this.getModel().id,
|
||||||
|
max_tokens: this.getModel().info.maxTokens,
|
||||||
|
messages: openAiMessages,
|
||||||
|
tools: openAiTools,
|
||||||
|
tool_choice: "auto",
|
||||||
|
}
|
||||||
|
const completion = await this.client.chat.completions.create(createParams)
|
||||||
|
const errorMessage = (completion as any).error?.message
|
||||||
|
if (errorMessage) {
|
||||||
|
throw new Error(errorMessage)
|
||||||
|
}
|
||||||
|
const anthropicMessage = convertToAnthropicMessage(completion)
|
||||||
|
return { message: anthropicMessage }
|
||||||
|
}
|
||||||
|
|
||||||
|
getModel(): { id: OpenAiNativeModelId; info: ModelInfo } {
|
||||||
|
const modelId = this.options.apiModelId
|
||||||
|
if (modelId && modelId in openAiNativeModels) {
|
||||||
|
const id = modelId as OpenAiNativeModelId
|
||||||
|
return { id, info: openAiNativeModels[id] }
|
||||||
|
}
|
||||||
|
return { id: openAiNativeDefaultModelId, info: openAiNativeModels[openAiNativeDefaultModelId] }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,6 +26,7 @@ type SecretKey =
|
|||||||
| "awsSessionToken"
|
| "awsSessionToken"
|
||||||
| "openAiApiKey"
|
| "openAiApiKey"
|
||||||
| "geminiApiKey"
|
| "geminiApiKey"
|
||||||
|
| "openAiNativeApiKey"
|
||||||
type GlobalStateKey =
|
type GlobalStateKey =
|
||||||
| "apiProvider"
|
| "apiProvider"
|
||||||
| "apiModelId"
|
| "apiModelId"
|
||||||
@@ -337,6 +338,7 @@ export class ClaudeDevProvider implements vscode.WebviewViewProvider {
|
|||||||
ollamaBaseUrl,
|
ollamaBaseUrl,
|
||||||
anthropicBaseUrl,
|
anthropicBaseUrl,
|
||||||
geminiApiKey,
|
geminiApiKey,
|
||||||
|
openAiNativeApiKey,
|
||||||
} = message.apiConfiguration
|
} = message.apiConfiguration
|
||||||
await this.updateGlobalState("apiProvider", apiProvider)
|
await this.updateGlobalState("apiProvider", apiProvider)
|
||||||
await this.updateGlobalState("apiModelId", apiModelId)
|
await this.updateGlobalState("apiModelId", apiModelId)
|
||||||
@@ -355,6 +357,7 @@ export class ClaudeDevProvider implements vscode.WebviewViewProvider {
|
|||||||
await this.updateGlobalState("ollamaBaseUrl", ollamaBaseUrl)
|
await this.updateGlobalState("ollamaBaseUrl", ollamaBaseUrl)
|
||||||
await this.updateGlobalState("anthropicBaseUrl", anthropicBaseUrl)
|
await this.updateGlobalState("anthropicBaseUrl", anthropicBaseUrl)
|
||||||
await this.storeSecret("geminiApiKey", geminiApiKey)
|
await this.storeSecret("geminiApiKey", geminiApiKey)
|
||||||
|
await this.storeSecret("openAiNativeApiKey", openAiNativeApiKey)
|
||||||
this.claudeDev?.updateApi(message.apiConfiguration)
|
this.claudeDev?.updateApi(message.apiConfiguration)
|
||||||
}
|
}
|
||||||
await this.postStateToWebview()
|
await this.postStateToWebview()
|
||||||
@@ -677,6 +680,7 @@ export class ClaudeDevProvider implements vscode.WebviewViewProvider {
|
|||||||
ollamaBaseUrl,
|
ollamaBaseUrl,
|
||||||
anthropicBaseUrl,
|
anthropicBaseUrl,
|
||||||
geminiApiKey,
|
geminiApiKey,
|
||||||
|
openAiNativeApiKey,
|
||||||
lastShownAnnouncementId,
|
lastShownAnnouncementId,
|
||||||
customInstructions,
|
customInstructions,
|
||||||
alwaysAllowReadOnly,
|
alwaysAllowReadOnly,
|
||||||
@@ -699,6 +703,7 @@ export class ClaudeDevProvider implements vscode.WebviewViewProvider {
|
|||||||
this.getGlobalState("ollamaBaseUrl") as Promise<string | undefined>,
|
this.getGlobalState("ollamaBaseUrl") as Promise<string | undefined>,
|
||||||
this.getGlobalState("anthropicBaseUrl") as Promise<string | undefined>,
|
this.getGlobalState("anthropicBaseUrl") as Promise<string | undefined>,
|
||||||
this.getSecret("geminiApiKey") as Promise<string | undefined>,
|
this.getSecret("geminiApiKey") as Promise<string | undefined>,
|
||||||
|
this.getSecret("openAiNativeApiKey") as Promise<string | undefined>,
|
||||||
this.getGlobalState("lastShownAnnouncementId") as Promise<string | undefined>,
|
this.getGlobalState("lastShownAnnouncementId") as Promise<string | undefined>,
|
||||||
this.getGlobalState("customInstructions") as Promise<string | undefined>,
|
this.getGlobalState("customInstructions") as Promise<string | undefined>,
|
||||||
this.getGlobalState("alwaysAllowReadOnly") as Promise<boolean | undefined>,
|
this.getGlobalState("alwaysAllowReadOnly") as Promise<boolean | undefined>,
|
||||||
@@ -738,6 +743,7 @@ export class ClaudeDevProvider implements vscode.WebviewViewProvider {
|
|||||||
ollamaBaseUrl,
|
ollamaBaseUrl,
|
||||||
anthropicBaseUrl,
|
anthropicBaseUrl,
|
||||||
geminiApiKey,
|
geminiApiKey,
|
||||||
|
openAiNativeApiKey,
|
||||||
},
|
},
|
||||||
lastShownAnnouncementId,
|
lastShownAnnouncementId,
|
||||||
customInstructions,
|
customInstructions,
|
||||||
@@ -817,6 +823,7 @@ export class ClaudeDevProvider implements vscode.WebviewViewProvider {
|
|||||||
"awsSessionToken",
|
"awsSessionToken",
|
||||||
"openAiApiKey",
|
"openAiApiKey",
|
||||||
"geminiApiKey",
|
"geminiApiKey",
|
||||||
|
"openAiNativeApiKey",
|
||||||
]
|
]
|
||||||
for (const key of secretKeys) {
|
for (const key of secretKeys) {
|
||||||
await this.storeSecret(key, undefined)
|
await this.storeSecret(key, undefined)
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
export type ApiProvider = "anthropic" | "openrouter" | "bedrock" | "vertex" | "openai" | "ollama" | "gemini"
|
export type ApiProvider =
|
||||||
|
| "anthropic"
|
||||||
|
| "openrouter"
|
||||||
|
| "bedrock"
|
||||||
|
| "vertex"
|
||||||
|
| "openai"
|
||||||
|
| "ollama"
|
||||||
|
| "gemini"
|
||||||
|
| "openai-native"
|
||||||
|
|
||||||
export interface ApiHandlerOptions {
|
export interface ApiHandlerOptions {
|
||||||
apiModelId?: string
|
apiModelId?: string
|
||||||
@@ -17,6 +25,7 @@ export interface ApiHandlerOptions {
|
|||||||
ollamaModelId?: string
|
ollamaModelId?: string
|
||||||
ollamaBaseUrl?: string
|
ollamaBaseUrl?: string
|
||||||
geminiApiKey?: string
|
geminiApiKey?: string
|
||||||
|
openAiNativeApiKey?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ApiConfiguration = ApiHandlerOptions & {
|
export type ApiConfiguration = ApiHandlerOptions & {
|
||||||
@@ -334,3 +343,42 @@ export const geminiModels = {
|
|||||||
outputPrice: 0,
|
outputPrice: 0,
|
||||||
},
|
},
|
||||||
} as const satisfies Record<string, ModelInfo>
|
} as const satisfies Record<string, ModelInfo>
|
||||||
|
|
||||||
|
// OpenAI Native
|
||||||
|
// https://openai.com/api/pricing/
|
||||||
|
export type OpenAiNativeModelId = keyof typeof openAiNativeModels
|
||||||
|
export const openAiNativeDefaultModelId: OpenAiNativeModelId = "o1-preview"
|
||||||
|
export const openAiNativeModels = {
|
||||||
|
"o1-preview": {
|
||||||
|
maxTokens: 32_768,
|
||||||
|
contextWindow: 128_000,
|
||||||
|
supportsImages: true,
|
||||||
|
supportsPromptCache: false,
|
||||||
|
inputPrice: 15,
|
||||||
|
outputPrice: 60,
|
||||||
|
},
|
||||||
|
"o1-mini": {
|
||||||
|
maxTokens: 65_536,
|
||||||
|
contextWindow: 128_000,
|
||||||
|
supportsImages: true,
|
||||||
|
supportsPromptCache: false,
|
||||||
|
inputPrice: 3,
|
||||||
|
outputPrice: 12,
|
||||||
|
},
|
||||||
|
"gpt-4o": {
|
||||||
|
maxTokens: 4_096,
|
||||||
|
contextWindow: 128_000,
|
||||||
|
supportsImages: true,
|
||||||
|
supportsPromptCache: false,
|
||||||
|
inputPrice: 5,
|
||||||
|
outputPrice: 15,
|
||||||
|
},
|
||||||
|
"gpt-4o-mini": {
|
||||||
|
maxTokens: 16_384,
|
||||||
|
contextWindow: 128_000,
|
||||||
|
supportsImages: true,
|
||||||
|
supportsPromptCache: false,
|
||||||
|
inputPrice: 0.15,
|
||||||
|
outputPrice: 0.6,
|
||||||
|
},
|
||||||
|
} as const satisfies Record<string, ModelInfo>
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { useEvent, useInterval } from "react-use"
|
|||||||
import {
|
import {
|
||||||
ApiConfiguration,
|
ApiConfiguration,
|
||||||
ModelInfo,
|
ModelInfo,
|
||||||
|
OpenAiNativeModelId,
|
||||||
anthropicDefaultModelId,
|
anthropicDefaultModelId,
|
||||||
anthropicModels,
|
anthropicModels,
|
||||||
bedrockDefaultModelId,
|
bedrockDefaultModelId,
|
||||||
@@ -19,6 +20,8 @@ import {
|
|||||||
geminiDefaultModelId,
|
geminiDefaultModelId,
|
||||||
geminiModels,
|
geminiModels,
|
||||||
openAiModelInfoSaneDefaults,
|
openAiModelInfoSaneDefaults,
|
||||||
|
openAiNativeDefaultModelId,
|
||||||
|
openAiNativeModels,
|
||||||
openRouterDefaultModelId,
|
openRouterDefaultModelId,
|
||||||
openRouterModels,
|
openRouterModels,
|
||||||
vertexDefaultModelId,
|
vertexDefaultModelId,
|
||||||
@@ -112,10 +115,11 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage }: ApiOptionsProps) => {
|
|||||||
onChange={handleInputChange("apiProvider")}
|
onChange={handleInputChange("apiProvider")}
|
||||||
style={{ minWidth: 130 }}>
|
style={{ minWidth: 130 }}>
|
||||||
<VSCodeOption value="anthropic">Anthropic</VSCodeOption>
|
<VSCodeOption value="anthropic">Anthropic</VSCodeOption>
|
||||||
|
<VSCodeOption value="openai-native">OpenAI</VSCodeOption>
|
||||||
<VSCodeOption value="openrouter">OpenRouter</VSCodeOption>
|
<VSCodeOption value="openrouter">OpenRouter</VSCodeOption>
|
||||||
|
<VSCodeOption value="gemini">Google Gemini</VSCodeOption>
|
||||||
<VSCodeOption value="bedrock">AWS Bedrock</VSCodeOption>
|
<VSCodeOption value="bedrock">AWS Bedrock</VSCodeOption>
|
||||||
<VSCodeOption value="vertex">GCP Vertex AI</VSCodeOption>
|
<VSCodeOption value="vertex">GCP Vertex AI</VSCodeOption>
|
||||||
<VSCodeOption value="gemini">Google Gemini</VSCodeOption>
|
|
||||||
<VSCodeOption value="openai">OpenAI Compatible</VSCodeOption>
|
<VSCodeOption value="openai">OpenAI Compatible</VSCodeOption>
|
||||||
<VSCodeOption value="ollama">Ollama</VSCodeOption>
|
<VSCodeOption value="ollama">Ollama</VSCodeOption>
|
||||||
</VSCodeDropdown>
|
</VSCodeDropdown>
|
||||||
@@ -174,6 +178,34 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage }: ApiOptionsProps) => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{selectedProvider === "openai-native" && (
|
||||||
|
<div>
|
||||||
|
<VSCodeTextField
|
||||||
|
value={apiConfiguration?.openAiNativeApiKey || ""}
|
||||||
|
style={{ width: "100%" }}
|
||||||
|
type="password"
|
||||||
|
onInput={handleInputChange("openAiNativeApiKey")}
|
||||||
|
placeholder="Enter API Key...">
|
||||||
|
<span style={{ fontWeight: 500 }}>OpenAI API Key</span>
|
||||||
|
</VSCodeTextField>
|
||||||
|
<p
|
||||||
|
style={{
|
||||||
|
fontSize: "12px",
|
||||||
|
marginTop: 3,
|
||||||
|
color: "var(--vscode-descriptionForeground)",
|
||||||
|
}}>
|
||||||
|
This key is stored locally and only used to make API requests from this extension.
|
||||||
|
{!apiConfiguration?.openAiNativeApiKey && (
|
||||||
|
<VSCodeLink
|
||||||
|
href="https://platform.openai.com/api-keys"
|
||||||
|
style={{ display: "inline", fontSize: "inherit" }}>
|
||||||
|
You can get an OpenAI API key by signing up here.
|
||||||
|
</VSCodeLink>
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{selectedProvider === "openrouter" && (
|
{selectedProvider === "openrouter" && (
|
||||||
<div>
|
<div>
|
||||||
<VSCodeTextField
|
<VSCodeTextField
|
||||||
@@ -490,6 +522,7 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage }: ApiOptionsProps) => {
|
|||||||
{selectedProvider === "bedrock" && createDropdown(bedrockModels)}
|
{selectedProvider === "bedrock" && createDropdown(bedrockModels)}
|
||||||
{selectedProvider === "vertex" && createDropdown(vertexModels)}
|
{selectedProvider === "vertex" && createDropdown(vertexModels)}
|
||||||
{selectedProvider === "gemini" && createDropdown(geminiModels)}
|
{selectedProvider === "gemini" && createDropdown(geminiModels)}
|
||||||
|
{selectedProvider === "openai-native" && createDropdown(openAiNativeModels)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ModelInfoView selectedModelId={selectedModelId} modelInfo={selectedModelInfo} />
|
<ModelInfoView selectedModelId={selectedModelId} modelInfo={selectedModelInfo} />
|
||||||
@@ -514,6 +547,7 @@ export const formatPrice = (price: number) => {
|
|||||||
|
|
||||||
const ModelInfoView = ({ selectedModelId, modelInfo }: { selectedModelId: string; modelInfo: ModelInfo }) => {
|
const ModelInfoView = ({ selectedModelId, modelInfo }: { selectedModelId: string; modelInfo: ModelInfo }) => {
|
||||||
const isGemini = Object.keys(geminiModels).includes(selectedModelId)
|
const isGemini = Object.keys(geminiModels).includes(selectedModelId)
|
||||||
|
const isO1 = (["o1-preview", "o1-mini"] as OpenAiNativeModelId[]).includes(selectedModelId as OpenAiNativeModelId)
|
||||||
return (
|
return (
|
||||||
<p style={{ fontSize: "12px", marginTop: "2px", color: "var(--vscode-descriptionForeground)" }}>
|
<p style={{ fontSize: "12px", marginTop: "2px", color: "var(--vscode-descriptionForeground)" }}>
|
||||||
<ModelInfoSupportsItem
|
<ModelInfoSupportsItem
|
||||||
@@ -533,32 +567,33 @@ const ModelInfoView = ({ selectedModelId, modelInfo }: { selectedModelId: string
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<span style={{ fontWeight: 500 }}>Max output:</span> {modelInfo?.maxTokens?.toLocaleString()} tokens
|
<span style={{ fontWeight: 500 }}>Max output:</span> {modelInfo?.maxTokens?.toLocaleString()} tokens
|
||||||
<br />
|
|
||||||
{modelInfo.inputPrice > 0 && (
|
{modelInfo.inputPrice > 0 && (
|
||||||
<>
|
<>
|
||||||
|
<br />
|
||||||
<span style={{ fontWeight: 500 }}>Input price:</span> {formatPrice(modelInfo.inputPrice)}/million
|
<span style={{ fontWeight: 500 }}>Input price:</span> {formatPrice(modelInfo.inputPrice)}/million
|
||||||
tokens
|
tokens
|
||||||
<br />
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{modelInfo.supportsPromptCache && modelInfo.cacheWritesPrice && modelInfo.cacheReadsPrice && (
|
{modelInfo.supportsPromptCache && modelInfo.cacheWritesPrice && modelInfo.cacheReadsPrice && (
|
||||||
<>
|
<>
|
||||||
|
<br />
|
||||||
<span style={{ fontWeight: 500 }}>Cache writes price:</span>{" "}
|
<span style={{ fontWeight: 500 }}>Cache writes price:</span>{" "}
|
||||||
{formatPrice(modelInfo.cacheWritesPrice || 0)}/million tokens
|
{formatPrice(modelInfo.cacheWritesPrice || 0)}/million tokens
|
||||||
<br />
|
<br />
|
||||||
<span style={{ fontWeight: 500 }}>Cache reads price:</span>{" "}
|
<span style={{ fontWeight: 500 }}>Cache reads price:</span>{" "}
|
||||||
{formatPrice(modelInfo.cacheReadsPrice || 0)}/million tokens
|
{formatPrice(modelInfo.cacheReadsPrice || 0)}/million tokens
|
||||||
<br />
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{modelInfo.outputPrice > 0 && (
|
{modelInfo.outputPrice > 0 && (
|
||||||
<>
|
<>
|
||||||
|
<br />
|
||||||
<span style={{ fontWeight: 500 }}>Output price:</span> {formatPrice(modelInfo.outputPrice)}/million
|
<span style={{ fontWeight: 500 }}>Output price:</span> {formatPrice(modelInfo.outputPrice)}/million
|
||||||
tokens
|
tokens
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{isGemini && (
|
{isGemini && (
|
||||||
<>
|
<>
|
||||||
|
<br />
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
fontStyle: "italic",
|
fontStyle: "italic",
|
||||||
@@ -573,6 +608,17 @@ const ModelInfoView = ({ selectedModelId, modelInfo }: { selectedModelId: string
|
|||||||
</span>
|
</span>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
{isO1 && (
|
||||||
|
<>
|
||||||
|
<br />
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
fontStyle: "italic",
|
||||||
|
}}>
|
||||||
|
* This model is newly released and may not be accessible to all users yet.
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</p>
|
</p>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -632,6 +678,8 @@ export function normalizeApiConfiguration(apiConfiguration?: ApiConfiguration) {
|
|||||||
return getProviderData(vertexModels, vertexDefaultModelId)
|
return getProviderData(vertexModels, vertexDefaultModelId)
|
||||||
case "gemini":
|
case "gemini":
|
||||||
return getProviderData(geminiModels, geminiDefaultModelId)
|
return getProviderData(geminiModels, geminiDefaultModelId)
|
||||||
|
case "openai-native":
|
||||||
|
return getProviderData(openAiNativeModels, openAiNativeDefaultModelId)
|
||||||
case "openai":
|
case "openai":
|
||||||
return {
|
return {
|
||||||
selectedProvider: provider,
|
selectedProvider: provider,
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
|
|||||||
config.openAiApiKey,
|
config.openAiApiKey,
|
||||||
config.ollamaModelId,
|
config.ollamaModelId,
|
||||||
config.geminiApiKey,
|
config.geminiApiKey,
|
||||||
|
config.openAiNativeApiKey,
|
||||||
].some((key) => key !== undefined)
|
].some((key) => key !== undefined)
|
||||||
: false
|
: false
|
||||||
setShowWelcome(!hasKey)
|
setShowWelcome(!hasKey)
|
||||||
|
|||||||
@@ -28,6 +28,11 @@ export function validateApiConfiguration(apiConfiguration?: ApiConfiguration): s
|
|||||||
return "You must provide a valid API key or choose a different provider."
|
return "You must provide a valid API key or choose a different provider."
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
case "openai-native":
|
||||||
|
if (!apiConfiguration.openAiNativeApiKey) {
|
||||||
|
return "You must provide a valid API key or choose a different provider."
|
||||||
|
}
|
||||||
|
break
|
||||||
case "openai":
|
case "openai":
|
||||||
if (
|
if (
|
||||||
!apiConfiguration.openAiBaseUrl ||
|
!apiConfiguration.openAiBaseUrl ||
|
||||||
|
|||||||
Reference in New Issue
Block a user