Compare commits

...
Author SHA1 Message Date
0xtoshii 56053a053e base 2025-06-24 13:20:12 -07:00
0xtoshiiandStvLz 8bd4f414f4 anthropic provider
Co-authored-by: StvLz <lizarazo.steven@gmail.com>
2025-06-24 13:19:54 -07:00
3 changed files with 155 additions and 85 deletions
@@ -54,6 +54,8 @@ import { DeepSeekProvider } from "./providers/DeepSeekProvider"
import { TogetherProvider } from "./providers/TogetherProvider"
import { OpenAICompatibleProvider } from "./providers/OpenAICompatible"
import { SambanovaProvider } from "./providers/SambanovaProvider"
import { AnthropicProvider } from "./providers/AnthropicProvider"
import { AskSageProvider } from "./providers/AskSageProvider"
interface ApiOptionsProps {
showModelOptions: boolean
@@ -64,7 +66,6 @@ interface ApiOptionsProps {
}
const SUPPORTED_THINKING_MODELS: Record<string, string[]> = {
anthropic: ["claude-3-7-sonnet-20250219", "claude-sonnet-4-20250514", "claude-opus-4-20250514"],
vertex: [
"claude-3-7-sonnet@20250219",
"claude-sonnet-4@20250514",
@@ -300,90 +301,23 @@ const ApiOptions = ({
</div>
)}
{selectedProvider === "asksage" && (
<div>
<VSCodeTextField
value={apiConfiguration?.asksageApiKey || ""}
style={{ width: "100%" }}
type="password"
onInput={handleInputChange("asksageApiKey")}
placeholder="Enter API Key...">
<span style={{ fontWeight: 500 }}>AskSage 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.
</p>
<VSCodeTextField
value={apiConfiguration?.asksageApiUrl || askSageDefaultURL}
style={{ width: "100%" }}
type="url"
onInput={handleInputChange("asksageApiUrl")}
placeholder="Enter AskSage API URL...">
<span style={{ fontWeight: 500 }}>AskSage API URL</span>
</VSCodeTextField>
</div>
{apiConfiguration && selectedProvider === "asksage" && (
<AskSageProvider
apiConfiguration={apiConfiguration}
handleInputChange={handleInputChange}
showModelOptions={showModelOptions}
isPopup={isPopup}
/>
)}
{selectedProvider === "anthropic" && (
<div>
<VSCodeTextField
value={apiConfiguration?.apiKey || ""}
style={{ width: "100%" }}
type="password"
onInput={handleInputChange("apiKey")}
placeholder="Enter API Key...">
<span style={{ fontWeight: 500 }}>Anthropic API Key</span>
</VSCodeTextField>
<VSCodeCheckbox
checked={anthropicBaseUrlSelected}
onChange={(e: any) => {
const isChecked = e.target.checked === true
setAnthropicBaseUrlSelected(isChecked)
if (!isChecked) {
setApiConfiguration({
...apiConfiguration,
anthropicBaseUrl: "",
})
}
}}>
Use custom base URL
</VSCodeCheckbox>
{anthropicBaseUrlSelected && (
<VSCodeTextField
value={apiConfiguration?.anthropicBaseUrl || ""}
style={{ width: "100%", marginTop: 3 }}
type="url"
onInput={handleInputChange("anthropicBaseUrl")}
placeholder="Default: https://api.anthropic.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?.apiKey && (
<VSCodeLink
href="https://console.anthropic.com/settings/keys"
style={{
display: "inline",
fontSize: "inherit",
}}>
You can get an Anthropic API key by signing up here.
</VSCodeLink>
)}
</p>
</div>
{apiConfiguration && selectedProvider === "anthropic" && (
<AnthropicProvider
apiConfiguration={apiConfiguration}
handleInputChange={handleInputChange}
showModelOptions={showModelOptions}
isPopup={isPopup}
setApiConfiguration={setApiConfiguration}
/>
)}
{selectedProvider === "claude-code" && (
@@ -1731,6 +1665,8 @@ const ApiOptions = ({
{selectedProvider !== "openrouter" &&
selectedProvider !== "cline" &&
selectedProvider !== "anthropic" &&
selectedProvider !== "asksage" &&
selectedProvider !== "openai" &&
selectedProvider !== "ollama" &&
selectedProvider !== "lmstudio" &&
@@ -1747,7 +1683,6 @@ const ApiOptions = ({
<label htmlFor="model-id">
<span style={{ fontWeight: 500 }}>Model</span>
</label>
{selectedProvider === "anthropic" && createDropdown(anthropicModels)}
{selectedProvider === "claude-code" && createDropdown(claudeCodeModels)}
{selectedProvider === "vertex" &&
createDropdown(apiConfiguration?.vertexRegion === "global" ? vertexGlobalModels : vertexModels)}
@@ -1758,7 +1693,6 @@ const ApiOptions = ({
apiConfiguration?.qwenApiLine === "china" ? mainlandQwenModels : internationalQwenModels,
)}
{selectedProvider === "doubao" && createDropdown(doubaoModels)}
{selectedProvider === "asksage" && createDropdown(askSageModels)}
{selectedProvider === "xai" && createDropdown(xaiModels)}
{selectedProvider === "cerebras" && createDropdown(cerebrasModels)}
{selectedProvider === "nebius" && createDropdown(nebiusModels)}
@@ -0,0 +1,79 @@
import { ApiConfiguration, anthropicModels } 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"
// Anthropic models that support thinking/reasoning mode
const SUPPORTED_THINKING_MODELS = ["claude-3-7-sonnet-20250219", "claude-sonnet-4-20250514", "claude-opus-4-20250514"]
/**
* Props for the AnthropicProvider component
*/
interface AnthropicProviderProps {
apiConfiguration: ApiConfiguration
handleInputChange: (field: keyof ApiConfiguration) => (event: any) => void
showModelOptions: boolean
isPopup?: boolean
setApiConfiguration?: (config: ApiConfiguration) => void
}
/**
* The Anthropic provider configuration component
*/
export const AnthropicProvider = ({
apiConfiguration,
handleInputChange,
showModelOptions,
isPopup,
setApiConfiguration,
}: AnthropicProviderProps) => {
// 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?.apiKey || ""}
onChange={handleInputChange("apiKey")}
providerName="Anthropic"
signupUrl="https://console.anthropic.com/settings/keys"
/>
<BaseUrlField
value={apiConfiguration?.anthropicBaseUrl}
onChange={handleFieldChange("anthropicBaseUrl")}
placeholder="Default: https://api.anthropic.com"
label="Use custom base URL"
/>
{showModelOptions && (
<>
<ModelSelector
models={anthropicModels}
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,57 @@
import { ApiConfiguration, askSageModels, askSageDefaultURL } from "@shared/api"
import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
import { ApiKeyField } from "../common/ApiKeyField"
import { ModelSelector } from "../common/ModelSelector"
import { ModelInfoView } from "../common/ModelInfoView"
import { normalizeApiConfiguration } from "../utils/providerUtils"
/**
* Props for the AskSageProvider component
*/
interface AskSageProviderProps {
apiConfiguration: ApiConfiguration
handleInputChange: (field: keyof ApiConfiguration) => (event: any) => void
showModelOptions: boolean
isPopup?: boolean
}
/**
* The AskSage provider configuration component
*/
export const AskSageProvider = ({ apiConfiguration, handleInputChange, showModelOptions, isPopup }: AskSageProviderProps) => {
// Get the normalized configuration
const { selectedModelId, selectedModelInfo } = normalizeApiConfiguration(apiConfiguration)
return (
<div>
<ApiKeyField
value={apiConfiguration?.asksageApiKey || ""}
onChange={handleInputChange("asksageApiKey")}
providerName="AskSage"
helpText="This key is stored locally and only used to make API requests from this extension."
/>
<VSCodeTextField
value={apiConfiguration?.asksageApiUrl || askSageDefaultURL}
style={{ width: "100%" }}
type="url"
onInput={handleInputChange("asksageApiUrl")}
placeholder="Enter AskSage API URL...">
<span style={{ fontWeight: 500 }}>AskSage API URL</span>
</VSCodeTextField>
{showModelOptions && (
<>
<ModelSelector
models={askSageModels}
selectedModelId={selectedModelId}
onChange={handleInputChange("apiModelId")}
label="Model"
/>
<ModelInfoView selectedModelId={selectedModelId} modelInfo={selectedModelInfo} isPopup={isPopup} />
</>
)}
</div>
)
}