Compare commits

...
Author SHA1 Message Date
0xtoshii ea2e373917 gemini 2025-06-25 13:03:13 -07:00
0xtoshiiandStvLz b1e5d0b86c base open ai
Co-authored-by: StvLz <lizarazo.steven@gmail.com>
2025-06-25 12:44:08 -07:00
3 changed files with 150 additions and 93 deletions
@@ -2,10 +2,7 @@ import { useExtensionState } from "@/context/ExtensionStateContext"
import { ModelsServiceClient } from "@/services/grpc-client"
import { getAsVar, VSC_DESCRIPTION_FOREGROUND } from "@/utils/vscStyles"
import {
anthropicModels,
ApiConfiguration,
askSageDefaultURL,
askSageModels,
bedrockDefaultModelId,
bedrockModels,
cerebrasModels,
@@ -17,7 +14,6 @@ import {
mainlandQwenModels,
ModelInfo,
nebiusModels,
openAiNativeModels,
vertexGlobalModels,
vertexModels,
xaiModels,
@@ -56,6 +52,8 @@ import { OpenAICompatibleProvider } from "./providers/OpenAICompatible"
import { SambanovaProvider } from "./providers/SambanovaProvider"
import { AnthropicProvider } from "./providers/AnthropicProvider"
import { AskSageProvider } from "./providers/AskSageProvider"
import { OpenAINativeProvider } from "./providers/OpenAINative"
import { GeminiProvider } from "./providers/GeminiProvider"
interface ApiOptionsProps {
showModelOptions: boolean
@@ -86,7 +84,6 @@ const SUPPORTED_THINKING_MODELS: Record<string, string[]> = {
"qwen-plus-latest",
"qwen-turbo-latest",
],
gemini: ["gemini-2.5-pro", "gemini-2.5-flash"],
}
// This is necessary to ensure dropdown opens downward, important for when this is used in popup
@@ -126,8 +123,6 @@ const ApiOptions = ({
const [ollamaModels, setOllamaModels] = useState<string[]>([])
const [lmStudioModels, setLmStudioModels] = useState<string[]>([])
const [vsCodeLmModels, setVsCodeLmModels] = useState<vscodemodels.LanguageModelChatSelector[]>([])
const [anthropicBaseUrlSelected, setAnthropicBaseUrlSelected] = useState(!!apiConfiguration?.anthropicBaseUrl)
const [geminiBaseUrlSelected, setGeminiBaseUrlSelected] = useState(!!apiConfiguration?.geminiBaseUrl)
const [awsEndpointSelected, setAwsEndpointSelected] = useState(!!apiConfiguration?.awsBedrockEndpoint)
const [modelConfigurationSelected, setModelConfigurationSelected] = useState(false)
const [isDescriptionExpanded, setIsDescriptionExpanded] = useState(false)
@@ -341,35 +336,13 @@ const ApiOptions = ({
</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>
{apiConfiguration && selectedProvider === "openai-native" && (
<OpenAINativeProvider
apiConfiguration={apiConfiguration}
handleInputChange={handleInputChange}
showModelOptions={showModelOptions}
isPopup={isPopup}
/>
)}
{selectedProvider === "qwen" && (
@@ -838,61 +811,14 @@ const ApiOptions = ({
</div>
)}
{selectedProvider === "gemini" && (
<div>
<VSCodeTextField
value={apiConfiguration?.geminiApiKey || ""}
style={{ width: "100%" }}
type="password"
onInput={handleInputChange("geminiApiKey")}
placeholder="Enter API Key...">
<span style={{ fontWeight: 500 }}>Gemini API Key</span>
</VSCodeTextField>
<VSCodeCheckbox
checked={geminiBaseUrlSelected}
onChange={(e: any) => {
const isChecked = e.target.checked === true
setGeminiBaseUrlSelected(isChecked)
if (!isChecked) {
setApiConfiguration({
...apiConfiguration,
geminiBaseUrl: "",
})
}
}}>
Use custom base URL
</VSCodeCheckbox>
{geminiBaseUrlSelected && (
<VSCodeTextField
value={apiConfiguration?.geminiBaseUrl || ""}
style={{ width: "100%", marginTop: 3 }}
type="url"
onInput={handleInputChange("geminiBaseUrl")}
placeholder="Default: https://generativelanguage.googleapis.com"
/>
)}
<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?.geminiApiKey && (
<VSCodeLink
href="https://aistudio.google.com/apikey"
style={{
display: "inline",
fontSize: "inherit",
}}>
You can get a Gemini API key by signing up here.
</VSCodeLink>
)}
</p>
</div>
{apiConfiguration && selectedProvider === "gemini" && (
<GeminiProvider
apiConfiguration={apiConfiguration}
handleInputChange={handleInputChange}
showModelOptions={showModelOptions}
isPopup={isPopup}
setApiConfiguration={setApiConfiguration}
/>
)}
{selectedProvider === "requesty" && (
@@ -1663,6 +1589,8 @@ const ApiOptions = ({
selectedProvider !== "mistral" &&
selectedProvider !== "deepseek" &&
selectedProvider !== "sambanova" &&
selectedProvider !== "openai-native" &&
selectedProvider !== "gemini" &&
showModelOptions && (
<>
<DropdownContainer zIndex={DROPDOWN_Z_INDEX - 2} className="dropdown-container">
@@ -1672,8 +1600,6 @@ const ApiOptions = ({
{selectedProvider === "claude-code" && createDropdown(claudeCodeModels)}
{selectedProvider === "vertex" &&
createDropdown(apiConfiguration?.vertexRegion === "global" ? vertexGlobalModels : vertexModels)}
{selectedProvider === "gemini" && createDropdown(geminiModels)}
{selectedProvider === "openai-native" && createDropdown(openAiNativeModels)}
{selectedProvider === "qwen" &&
createDropdown(
apiConfiguration?.qwenApiLine === "china" ? mainlandQwenModels : internationalQwenModels,
@@ -0,0 +1,79 @@
import { ApiConfiguration, geminiModels } from "@shared/api"
import { ApiKeyField } from "../common/ApiKeyField"
import { BaseUrlField } from "../common/BaseUrlField"
import { ModelSelector } from "../common/ModelSelector"
import { ModelInfoView } from "../common/ModelInfoView"
import { normalizeApiConfiguration } from "../utils/providerUtils"
import ThinkingBudgetSlider from "../ThinkingBudgetSlider"
// Gemini models that support thinking/reasoning mode
const SUPPORTED_THINKING_MODELS = ["gemini-2.5-pro", "gemini-2.5-flash"]
/**
* Props for the GeminiProvider component
*/
interface GeminiProviderProps {
apiConfiguration: ApiConfiguration
handleInputChange: (field: keyof ApiConfiguration) => (event: any) => void
showModelOptions: boolean
isPopup?: boolean
setApiConfiguration?: (config: ApiConfiguration) => void
}
/**
* The Gemini provider configuration component
*/
export const GeminiProvider = ({
apiConfiguration,
handleInputChange,
showModelOptions,
isPopup,
setApiConfiguration,
}: GeminiProviderProps) => {
// Get the normalized configuration
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration)
// Create a wrapper for handling field changes more directly
const handleFieldChange = (field: keyof ApiConfiguration) => (value: string) => {
handleInputChange(field)({ target: { value } })
}
return (
<div>
<ApiKeyField
value={apiConfiguration?.geminiApiKey || ""}
onChange={handleInputChange("geminiApiKey")}
providerName="Gemini"
signupUrl="https://aistudio.google.com/apikey"
/>
<BaseUrlField
value={apiConfiguration?.geminiBaseUrl}
onChange={handleFieldChange("geminiBaseUrl")}
placeholder="Default: https://generativelanguage.googleapis.com"
label="Use custom base URL"
/>
{showModelOptions && (
<>
<ModelSelector
models={geminiModels}
selectedModelId={selectedModelId}
onChange={handleInputChange("apiModelId")}
label="Model"
/>
{SUPPORTED_THINKING_MODELS.includes(selectedModelId) && setApiConfiguration && (
<ThinkingBudgetSlider
apiConfiguration={apiConfiguration}
setApiConfiguration={setApiConfiguration}
maxBudget={selectedModelInfo.thinkingConfig?.maxBudget}
/>
)}
<ModelInfoView selectedModelId={selectedModelId} modelInfo={selectedModelInfo} isPopup={isPopup} />
</>
)}
</div>
)
}
@@ -0,0 +1,52 @@
import { ApiConfiguration, openAiNativeModels } from "@shared/api"
import { ApiKeyField } from "../common/ApiKeyField"
import { ModelSelector } from "../common/ModelSelector"
import { ModelInfoView } from "../common/ModelInfoView"
import { normalizeApiConfiguration } from "../utils/providerUtils"
/**
* Props for the OpenAINativeProvider component
*/
interface OpenAINativeProviderProps {
apiConfiguration: ApiConfiguration
handleInputChange: (field: keyof ApiConfiguration) => (event: any) => void
showModelOptions: boolean
isPopup?: boolean
}
/**
* The OpenAI (native) provider configuration component
*/
export const OpenAINativeProvider = ({
apiConfiguration,
handleInputChange,
showModelOptions,
isPopup,
}: OpenAINativeProviderProps) => {
// Get the normalized configuration
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration)
return (
<div>
<ApiKeyField
value={apiConfiguration?.openAiNativeApiKey || ""}
onChange={handleInputChange("openAiNativeApiKey")}
providerName="OpenAI"
signupUrl="https://platform.openai.com/api-keys"
/>
{showModelOptions && (
<>
<ModelSelector
models={openAiNativeModels}
selectedModelId={selectedModelId}
onChange={handleInputChange("apiModelId")}
label="Model"
/>
<ModelInfoView selectedModelId={selectedModelId} modelInfo={selectedModelInfo} isPopup={isPopup} />
</>
)}
</div>
)
}