Skip to content

Commit 91725fd

Browse files
committed
Add new ApiKey component and use with Anthropic
Signed-off-by: Geoff Wilson <[email protected]>
1 parent 39a1edb commit 91725fd

File tree

3 files changed

+81
-33
lines changed

3 files changed

+81
-33
lines changed

packages/types/src/provider-settings.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ const vertexSchema = apiModelIdProviderModelSchema.extend({
113113
const openAiSchema = baseProviderSettingsSchema.extend({
114114
openAiBaseUrl: z.string().optional(),
115115
openAiApiKey: z.string().optional(),
116+
openAiApiKeyUseEnvVar: z.boolean().optional(),
116117
openAiLegacyFormat: z.boolean().optional(),
117118
openAiR1FormatEnabled: z.boolean().optional(),
118119
openAiModelId: z.string().optional(),
@@ -293,6 +294,7 @@ export const PROVIDER_SETTINGS_KEYS = keysOf<ProviderSettings>()([
293294
// OpenAI
294295
"openAiBaseUrl",
295296
"openAiApiKey",
297+
"openAiApiKeyUseEnvVar",
296298
"openAiLegacyFormat",
297299
"openAiR1FormatEnabled",
298300
"openAiModelId",
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { useState } from "react"
2+
import { Checkbox } from "vscrui"
3+
import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
4+
import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink"
5+
import { t } from "i18next"
6+
7+
type ApiKeyProps = {
8+
apiKey: string
9+
apiKeyEnvVar: string
10+
setApiKey: (value: string) => void
11+
setApiKeyUseEnvVar: (value: boolean) => void
12+
apiKeyLabel: string
13+
apiKeyUseEnvVar: boolean
14+
getApiKeyUrl?: string
15+
getApiKeyLabel?: string
16+
disabled?: boolean
17+
}
18+
19+
export const ApiKey = ({
20+
apiKey,
21+
apiKeyEnvVar,
22+
setApiKey,
23+
setApiKeyUseEnvVar,
24+
apiKeyLabel,
25+
apiKeyUseEnvVar,
26+
getApiKeyUrl,
27+
getApiKeyLabel,
28+
disabled = false,
29+
}: ApiKeyProps) => {
30+
31+
const env = (window as any).PROCESS_ENV || {}
32+
const apiKeyEnvVarExists = !!env[apiKeyEnvVar]
33+
const [useEnvVar, setUseEnvVar] = useState(apiKeyUseEnvVar && apiKeyEnvVarExists)
34+
35+
const handleUseEnvVarChange = (checked: boolean) => {
36+
setUseEnvVar(checked)
37+
setApiKeyUseEnvVar(checked)
38+
}
39+
40+
return (
41+
<>
42+
<VSCodeTextField
43+
value={apiKey || ""}
44+
type="password"
45+
onInput={e => setApiKey((e.target as HTMLInputElement).value)}
46+
placeholder={t("settings:placeholders.apiKey")}
47+
className="w-full"
48+
disabled={useEnvVar || disabled}>
49+
<label className="block font-medium mb-1">{apiKeyLabel}</label>
50+
</VSCodeTextField>
51+
<div className="text-sm text-vscode-descriptionForeground -mt-2">
52+
{t("settings:providers.apiKeyStorageNotice")}
53+
</div>
54+
<Checkbox
55+
checked={useEnvVar}
56+
onChange={handleUseEnvVarChange}
57+
className="mb-2"
58+
disabled={!apiKeyEnvVarExists}>
59+
{t("settings:providers.apiKeyUseEnvVar", { name: apiKeyEnvVar })}
60+
</Checkbox>
61+
{!(apiKey || useEnvVar) && getApiKeyUrl && getApiKeyLabel && (
62+
<VSCodeButtonLink href={getApiKeyUrl} appearance="secondary">
63+
{getApiKeyLabel}
64+
</VSCodeButtonLink>
65+
)}
66+
</>
67+
)
68+
}

webview-ui/src/components/settings/providers/Anthropic.tsx

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { useAppTranslation } from "@src/i18n/TranslationContext"
88
import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink"
99

1010
import { inputEventTransform, noTransform } from "../transforms"
11+
import { ApiKey } from "../ApiKey"
1112

1213
type AnthropicProps = {
1314
apiConfiguration: ProviderSettings
@@ -29,41 +30,18 @@ export const Anthropic = ({ apiConfiguration, setApiConfigurationField }: Anthro
2930
[setApiConfigurationField],
3031
)
3132

32-
const env = (window as any).PROCESS_ENV || {}
33-
const apiKeyEnvVarExists = !!env["ANTHROPIC_API_KEY"]
34-
const [useApiKeyEnvVar, setUseApiKeyEnvVar] = useState(!!apiConfiguration?.anthropicApiKeyUseEnvVar && apiKeyEnvVarExists)
35-
36-
const handleUseApiKeyEnvVarChange = (checked: boolean) => {
37-
setUseApiKeyEnvVar(checked)
38-
setApiConfigurationField("anthropicApiKeyUseEnvVar", checked)
39-
}
40-
4133
return (
4234
<>
43-
<VSCodeTextField
44-
value={apiConfiguration?.apiKey || ""}
45-
type="password"
46-
onInput={handleInputChange("apiKey")}
47-
placeholder={t("settings:placeholders.apiKey")}
48-
className="w-full"
49-
disabled={useApiKeyEnvVar}>
50-
<label className="block font-medium mb-1">{t("settings:providers.anthropicApiKey")}</label>
51-
</VSCodeTextField>
52-
<div className="text-sm text-vscode-descriptionForeground -mt-2">
53-
{t("settings:providers.apiKeyStorageNotice")}
54-
</div>
55-
<Checkbox
56-
checked={useApiKeyEnvVar}
57-
onChange={handleUseApiKeyEnvVarChange}
58-
className="mb-2"
59-
disabled={!apiKeyEnvVarExists}>
60-
{t("settings:providers.apiKeyUseEnvVar", { name: "ANTHROPIC_API_KEY"})}
61-
</Checkbox>
62-
{(!(apiConfiguration?.apiKey || apiConfiguration?.anthropicApiKeyUseEnvVar)) && (
63-
<VSCodeButtonLink href="https://console.anthropic.com/settings/keys" appearance="secondary">
64-
{t("settings:providers.getAnthropicApiKey")}
65-
</VSCodeButtonLink>
66-
)}
35+
<ApiKey
36+
apiKey={apiConfiguration?.apiKey || ""}
37+
apiKeyEnvVar="ANTHROPIC_API_KEY"
38+
apiKeyUseEnvVar={!!apiConfiguration?.anthropicApiKeyUseEnvVar}
39+
setApiKey={(value: string) => setApiConfigurationField("apiKey", value)}
40+
setApiKeyUseEnvVar={(value: boolean) => setApiConfigurationField("anthropicApiKeyUseEnvVar", value)}
41+
apiKeyLabel={t("settings:providers.anthropicApiKey")}
42+
getApiKeyUrl="https://console.anthropic.com/settings/keys"
43+
getApiKeyLabel={t("settings:providers.getAnthropicApiKey")}
44+
/>
6745
<div>
6846
<Checkbox
6947
checked={anthropicBaseUrlSelected}

0 commit comments

Comments
 (0)