refactor: split simple api-key auth providers
This commit is contained in:
538
src/commands/auth-choice.apply.api-key-providers.ts
Normal file
538
src/commands/auth-choice.apply.api-key-providers.ts
Normal file
@@ -0,0 +1,538 @@
|
||||
import { ensureAuthProfileStore, resolveAuthProfileOrder } from "../agents/auth-profiles.js";
|
||||
import type { SecretInput } from "../config/types.secrets.js";
|
||||
import { normalizeApiKeyInput, validateApiKeyInput } from "./auth-choice.api-key.js";
|
||||
import { ensureApiKeyFromOptionEnvOrPrompt } from "./auth-choice.apply-helpers.js";
|
||||
import type { ApplyAuthChoiceParams, ApplyAuthChoiceResult } from "./auth-choice.apply.js";
|
||||
import type { ApiKeyStorageOptions } from "./onboard-auth.credentials.js";
|
||||
import {
|
||||
applyAuthProfileConfig,
|
||||
applyKilocodeConfig,
|
||||
applyKilocodeProviderConfig,
|
||||
applyKimiCodeConfig,
|
||||
applyKimiCodeProviderConfig,
|
||||
applyLitellmConfig,
|
||||
applyLitellmProviderConfig,
|
||||
applyMistralConfig,
|
||||
applyMistralProviderConfig,
|
||||
applyModelStudioConfig,
|
||||
applyModelStudioConfigCn,
|
||||
applyModelStudioProviderConfig,
|
||||
applyModelStudioProviderConfigCn,
|
||||
applyMoonshotConfig,
|
||||
applyMoonshotConfigCn,
|
||||
applyMoonshotProviderConfig,
|
||||
applyMoonshotProviderConfigCn,
|
||||
applyOpencodeGoConfig,
|
||||
applyOpencodeGoProviderConfig,
|
||||
applyOpencodeZenConfig,
|
||||
applyOpencodeZenProviderConfig,
|
||||
applyQianfanConfig,
|
||||
applyQianfanProviderConfig,
|
||||
applySyntheticConfig,
|
||||
applySyntheticProviderConfig,
|
||||
applyTogetherConfig,
|
||||
applyTogetherProviderConfig,
|
||||
applyVeniceConfig,
|
||||
applyVeniceProviderConfig,
|
||||
applyVercelAiGatewayConfig,
|
||||
applyVercelAiGatewayProviderConfig,
|
||||
applyXiaomiConfig,
|
||||
applyXiaomiProviderConfig,
|
||||
KILOCODE_DEFAULT_MODEL_REF,
|
||||
KIMI_CODING_MODEL_REF,
|
||||
LITELLM_DEFAULT_MODEL_REF,
|
||||
MISTRAL_DEFAULT_MODEL_REF,
|
||||
MODELSTUDIO_DEFAULT_MODEL_REF,
|
||||
MOONSHOT_DEFAULT_MODEL_REF,
|
||||
QIANFAN_DEFAULT_MODEL_REF,
|
||||
setKilocodeApiKey,
|
||||
setKimiCodingApiKey,
|
||||
setLitellmApiKey,
|
||||
setMistralApiKey,
|
||||
setModelStudioApiKey,
|
||||
setMoonshotApiKey,
|
||||
setOpencodeGoApiKey,
|
||||
setOpencodeZenApiKey,
|
||||
setQianfanApiKey,
|
||||
setSyntheticApiKey,
|
||||
setTogetherApiKey,
|
||||
setVeniceApiKey,
|
||||
setVercelAiGatewayApiKey,
|
||||
setXiaomiApiKey,
|
||||
SYNTHETIC_DEFAULT_MODEL_REF,
|
||||
TOGETHER_DEFAULT_MODEL_REF,
|
||||
VENICE_DEFAULT_MODEL_REF,
|
||||
VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF,
|
||||
XIAOMI_DEFAULT_MODEL_REF,
|
||||
} from "./onboard-auth.js";
|
||||
import type { AuthChoice, SecretInputMode } from "./onboard-types.js";
|
||||
import { OPENCODE_GO_DEFAULT_MODEL_REF } from "./opencode-go-model-default.js";
|
||||
import { OPENCODE_ZEN_DEFAULT_MODEL } from "./opencode-zen-model-default.js";
|
||||
|
||||
type ApiKeyProviderConfigApplier = (
|
||||
config: ApplyAuthChoiceParams["config"],
|
||||
) => ApplyAuthChoiceParams["config"];
|
||||
|
||||
type ApplyProviderDefaultModel = (args: {
|
||||
defaultModel: string;
|
||||
applyDefaultConfig: ApiKeyProviderConfigApplier;
|
||||
applyProviderConfig: ApiKeyProviderConfigApplier;
|
||||
noteDefault?: string;
|
||||
}) => Promise<void>;
|
||||
|
||||
type ApplyApiKeyProviderParams = {
|
||||
params: ApplyAuthChoiceParams;
|
||||
authChoice: AuthChoice;
|
||||
config: ApplyAuthChoiceParams["config"];
|
||||
setConfig: (config: ApplyAuthChoiceParams["config"]) => void;
|
||||
getConfig: () => ApplyAuthChoiceParams["config"];
|
||||
normalizedTokenProvider?: string;
|
||||
requestedSecretInputMode?: SecretInputMode;
|
||||
applyProviderDefaultModel: ApplyProviderDefaultModel;
|
||||
getAgentModelOverride: () => string | undefined;
|
||||
};
|
||||
|
||||
type SimpleApiKeyProviderFlow = {
|
||||
provider: Parameters<typeof ensureApiKeyFromOptionEnvOrPrompt>[0]["provider"];
|
||||
profileId: string;
|
||||
expectedProviders: string[];
|
||||
envLabel: string;
|
||||
promptMessage: string;
|
||||
setCredential: (
|
||||
apiKey: SecretInput,
|
||||
agentDir?: string,
|
||||
options?: ApiKeyStorageOptions,
|
||||
) => void | Promise<void>;
|
||||
defaultModel: string;
|
||||
applyDefaultConfig: ApiKeyProviderConfigApplier;
|
||||
applyProviderConfig: ApiKeyProviderConfigApplier;
|
||||
tokenProvider?: string;
|
||||
normalize?: (value: string) => string;
|
||||
validate?: (value: string) => string | undefined;
|
||||
noteDefault?: string;
|
||||
noteMessage?: string;
|
||||
noteTitle?: string;
|
||||
};
|
||||
|
||||
const SIMPLE_API_KEY_PROVIDER_FLOWS: Partial<Record<AuthChoice, SimpleApiKeyProviderFlow>> = {
|
||||
"ai-gateway-api-key": {
|
||||
provider: "vercel-ai-gateway",
|
||||
profileId: "vercel-ai-gateway:default",
|
||||
expectedProviders: ["vercel-ai-gateway"],
|
||||
envLabel: "AI_GATEWAY_API_KEY",
|
||||
promptMessage: "Enter Vercel AI Gateway API key",
|
||||
setCredential: setVercelAiGatewayApiKey,
|
||||
defaultModel: VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applyVercelAiGatewayConfig,
|
||||
applyProviderConfig: applyVercelAiGatewayProviderConfig,
|
||||
noteDefault: VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF,
|
||||
},
|
||||
"moonshot-api-key": {
|
||||
provider: "moonshot",
|
||||
profileId: "moonshot:default",
|
||||
expectedProviders: ["moonshot"],
|
||||
envLabel: "MOONSHOT_API_KEY",
|
||||
promptMessage: "Enter Moonshot API key",
|
||||
setCredential: setMoonshotApiKey,
|
||||
defaultModel: MOONSHOT_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applyMoonshotConfig,
|
||||
applyProviderConfig: applyMoonshotProviderConfig,
|
||||
},
|
||||
"moonshot-api-key-cn": {
|
||||
provider: "moonshot",
|
||||
profileId: "moonshot:default",
|
||||
expectedProviders: ["moonshot"],
|
||||
envLabel: "MOONSHOT_API_KEY",
|
||||
promptMessage: "Enter Moonshot API key (.cn)",
|
||||
setCredential: setMoonshotApiKey,
|
||||
defaultModel: MOONSHOT_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applyMoonshotConfigCn,
|
||||
applyProviderConfig: applyMoonshotProviderConfigCn,
|
||||
},
|
||||
"kimi-code-api-key": {
|
||||
provider: "kimi-coding",
|
||||
profileId: "kimi-coding:default",
|
||||
expectedProviders: ["kimi-code", "kimi-coding"],
|
||||
envLabel: "KIMI_API_KEY",
|
||||
promptMessage: "Enter Kimi Coding API key",
|
||||
setCredential: setKimiCodingApiKey,
|
||||
defaultModel: KIMI_CODING_MODEL_REF,
|
||||
applyDefaultConfig: applyKimiCodeConfig,
|
||||
applyProviderConfig: applyKimiCodeProviderConfig,
|
||||
noteDefault: KIMI_CODING_MODEL_REF,
|
||||
noteMessage: [
|
||||
"Kimi Coding uses a dedicated endpoint and API key.",
|
||||
"Get your API key at: https://www.kimi.com/code/en",
|
||||
].join("\n"),
|
||||
noteTitle: "Kimi Coding",
|
||||
},
|
||||
"xiaomi-api-key": {
|
||||
provider: "xiaomi",
|
||||
profileId: "xiaomi:default",
|
||||
expectedProviders: ["xiaomi"],
|
||||
envLabel: "XIAOMI_API_KEY",
|
||||
promptMessage: "Enter Xiaomi API key",
|
||||
setCredential: setXiaomiApiKey,
|
||||
defaultModel: XIAOMI_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applyXiaomiConfig,
|
||||
applyProviderConfig: applyXiaomiProviderConfig,
|
||||
noteDefault: XIAOMI_DEFAULT_MODEL_REF,
|
||||
},
|
||||
"mistral-api-key": {
|
||||
provider: "mistral",
|
||||
profileId: "mistral:default",
|
||||
expectedProviders: ["mistral"],
|
||||
envLabel: "MISTRAL_API_KEY",
|
||||
promptMessage: "Enter Mistral API key",
|
||||
setCredential: setMistralApiKey,
|
||||
defaultModel: MISTRAL_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applyMistralConfig,
|
||||
applyProviderConfig: applyMistralProviderConfig,
|
||||
noteDefault: MISTRAL_DEFAULT_MODEL_REF,
|
||||
},
|
||||
"venice-api-key": {
|
||||
provider: "venice",
|
||||
profileId: "venice:default",
|
||||
expectedProviders: ["venice"],
|
||||
envLabel: "VENICE_API_KEY",
|
||||
promptMessage: "Enter Venice AI API key",
|
||||
setCredential: setVeniceApiKey,
|
||||
defaultModel: VENICE_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applyVeniceConfig,
|
||||
applyProviderConfig: applyVeniceProviderConfig,
|
||||
noteDefault: VENICE_DEFAULT_MODEL_REF,
|
||||
noteMessage: [
|
||||
"Venice AI provides privacy-focused inference with uncensored models.",
|
||||
"Get your API key at: https://venice.ai/settings/api",
|
||||
"Supports 'private' (fully private) and 'anonymized' (proxy) modes.",
|
||||
].join("\n"),
|
||||
noteTitle: "Venice AI",
|
||||
},
|
||||
"opencode-zen": {
|
||||
provider: "opencode",
|
||||
profileId: "opencode:default",
|
||||
expectedProviders: ["opencode", "opencode-go"],
|
||||
envLabel: "OPENCODE_API_KEY",
|
||||
promptMessage: "Enter OpenCode API key",
|
||||
setCredential: setOpencodeZenApiKey,
|
||||
defaultModel: OPENCODE_ZEN_DEFAULT_MODEL,
|
||||
applyDefaultConfig: applyOpencodeZenConfig,
|
||||
applyProviderConfig: applyOpencodeZenProviderConfig,
|
||||
noteDefault: OPENCODE_ZEN_DEFAULT_MODEL,
|
||||
noteMessage: [
|
||||
"OpenCode uses one API key across the Zen and Go catalogs.",
|
||||
"Zen provides access to Claude, GPT, Gemini, and more models.",
|
||||
"Get your API key at: https://opencode.ai/auth",
|
||||
"Choose the Zen catalog when you want the curated multi-model proxy.",
|
||||
].join("\n"),
|
||||
noteTitle: "OpenCode",
|
||||
},
|
||||
"opencode-go": {
|
||||
provider: "opencode-go",
|
||||
profileId: "opencode-go:default",
|
||||
expectedProviders: ["opencode", "opencode-go"],
|
||||
envLabel: "OPENCODE_API_KEY",
|
||||
promptMessage: "Enter OpenCode API key",
|
||||
setCredential: setOpencodeGoApiKey,
|
||||
defaultModel: OPENCODE_GO_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applyOpencodeGoConfig,
|
||||
applyProviderConfig: applyOpencodeGoProviderConfig,
|
||||
noteDefault: OPENCODE_GO_DEFAULT_MODEL_REF,
|
||||
noteMessage: [
|
||||
"OpenCode uses one API key across the Zen and Go catalogs.",
|
||||
"Go provides access to Kimi, GLM, and MiniMax models through the Go catalog.",
|
||||
"Get your API key at: https://opencode.ai/auth",
|
||||
"Choose the Go catalog when you want the OpenCode-hosted Kimi/GLM/MiniMax lineup.",
|
||||
].join("\n"),
|
||||
noteTitle: "OpenCode",
|
||||
},
|
||||
"together-api-key": {
|
||||
provider: "together",
|
||||
profileId: "together:default",
|
||||
expectedProviders: ["together"],
|
||||
envLabel: "TOGETHER_API_KEY",
|
||||
promptMessage: "Enter Together AI API key",
|
||||
setCredential: setTogetherApiKey,
|
||||
defaultModel: TOGETHER_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applyTogetherConfig,
|
||||
applyProviderConfig: applyTogetherProviderConfig,
|
||||
noteDefault: TOGETHER_DEFAULT_MODEL_REF,
|
||||
noteMessage: [
|
||||
"Together AI provides access to leading open-source models including Llama, DeepSeek, Qwen, and more.",
|
||||
"Get your API key at: https://api.together.xyz/settings/api-keys",
|
||||
].join("\n"),
|
||||
noteTitle: "Together AI",
|
||||
},
|
||||
"qianfan-api-key": {
|
||||
provider: "qianfan",
|
||||
profileId: "qianfan:default",
|
||||
expectedProviders: ["qianfan"],
|
||||
envLabel: "QIANFAN_API_KEY",
|
||||
promptMessage: "Enter QIANFAN API key",
|
||||
setCredential: setQianfanApiKey,
|
||||
defaultModel: QIANFAN_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applyQianfanConfig,
|
||||
applyProviderConfig: applyQianfanProviderConfig,
|
||||
noteDefault: QIANFAN_DEFAULT_MODEL_REF,
|
||||
noteMessage: [
|
||||
"Get your API key at: https://console.bce.baidu.com/qianfan/ais/console/apiKey",
|
||||
"API key format: bce-v3/ALTAK-...",
|
||||
].join("\n"),
|
||||
noteTitle: "QIANFAN",
|
||||
},
|
||||
"kilocode-api-key": {
|
||||
provider: "kilocode",
|
||||
profileId: "kilocode:default",
|
||||
expectedProviders: ["kilocode"],
|
||||
envLabel: "KILOCODE_API_KEY",
|
||||
promptMessage: "Enter Kilo Gateway API key",
|
||||
setCredential: setKilocodeApiKey,
|
||||
defaultModel: KILOCODE_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applyKilocodeConfig,
|
||||
applyProviderConfig: applyKilocodeProviderConfig,
|
||||
noteDefault: KILOCODE_DEFAULT_MODEL_REF,
|
||||
},
|
||||
"modelstudio-api-key-cn": {
|
||||
provider: "modelstudio",
|
||||
profileId: "modelstudio:default",
|
||||
expectedProviders: ["modelstudio"],
|
||||
envLabel: "MODELSTUDIO_API_KEY",
|
||||
promptMessage: "Enter Alibaba Cloud Model Studio Coding Plan API key (China)",
|
||||
setCredential: setModelStudioApiKey,
|
||||
defaultModel: MODELSTUDIO_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applyModelStudioConfigCn,
|
||||
applyProviderConfig: applyModelStudioProviderConfigCn,
|
||||
noteDefault: MODELSTUDIO_DEFAULT_MODEL_REF,
|
||||
noteMessage: [
|
||||
"Get your API key at: https://bailian.console.aliyun.com/",
|
||||
"Endpoint: coding.dashscope.aliyuncs.com",
|
||||
"Models: qwen3.5-plus, glm-4.7, kimi-k2.5, MiniMax-M2.5, etc.",
|
||||
].join("\n"),
|
||||
noteTitle: "Alibaba Cloud Model Studio Coding Plan (China)",
|
||||
normalize: (value) => String(value ?? "").trim(),
|
||||
validate: (value) => (String(value ?? "").trim() ? undefined : "Required"),
|
||||
},
|
||||
"modelstudio-api-key": {
|
||||
provider: "modelstudio",
|
||||
profileId: "modelstudio:default",
|
||||
expectedProviders: ["modelstudio"],
|
||||
envLabel: "MODELSTUDIO_API_KEY",
|
||||
promptMessage: "Enter Alibaba Cloud Model Studio Coding Plan API key (Global/Intl)",
|
||||
setCredential: setModelStudioApiKey,
|
||||
defaultModel: MODELSTUDIO_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applyModelStudioConfig,
|
||||
applyProviderConfig: applyModelStudioProviderConfig,
|
||||
noteDefault: MODELSTUDIO_DEFAULT_MODEL_REF,
|
||||
noteMessage: [
|
||||
"Get your API key at: https://bailian.console.aliyun.com/",
|
||||
"Endpoint: coding-intl.dashscope.aliyuncs.com",
|
||||
"Models: qwen3.5-plus, glm-4.7, kimi-k2.5, MiniMax-M2.5, etc.",
|
||||
].join("\n"),
|
||||
noteTitle: "Alibaba Cloud Model Studio Coding Plan (Global/Intl)",
|
||||
normalize: (value) => String(value ?? "").trim(),
|
||||
validate: (value) => (String(value ?? "").trim() ? undefined : "Required"),
|
||||
},
|
||||
"synthetic-api-key": {
|
||||
provider: "synthetic",
|
||||
profileId: "synthetic:default",
|
||||
expectedProviders: ["synthetic"],
|
||||
envLabel: "SYNTHETIC_API_KEY",
|
||||
promptMessage: "Enter Synthetic API key",
|
||||
setCredential: setSyntheticApiKey,
|
||||
defaultModel: SYNTHETIC_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applySyntheticConfig,
|
||||
applyProviderConfig: applySyntheticProviderConfig,
|
||||
normalize: (value) => String(value ?? "").trim(),
|
||||
validate: (value) => (String(value ?? "").trim() ? undefined : "Required"),
|
||||
},
|
||||
};
|
||||
|
||||
async function applyApiKeyProviderWithDefaultModel({
|
||||
params,
|
||||
config,
|
||||
setConfig,
|
||||
getConfig,
|
||||
normalizedTokenProvider,
|
||||
requestedSecretInputMode,
|
||||
applyProviderDefaultModel,
|
||||
getAgentModelOverride,
|
||||
provider,
|
||||
profileId,
|
||||
expectedProviders,
|
||||
envLabel,
|
||||
promptMessage,
|
||||
setCredential,
|
||||
defaultModel,
|
||||
applyDefaultConfig,
|
||||
applyProviderConfig,
|
||||
noteMessage,
|
||||
noteTitle,
|
||||
tokenProvider = normalizedTokenProvider,
|
||||
normalize = normalizeApiKeyInput,
|
||||
validate = validateApiKeyInput,
|
||||
noteDefault = defaultModel,
|
||||
}: ApplyApiKeyProviderParams & {
|
||||
provider: Parameters<typeof ensureApiKeyFromOptionEnvOrPrompt>[0]["provider"];
|
||||
profileId: string;
|
||||
expectedProviders: string[];
|
||||
envLabel: string;
|
||||
promptMessage: string;
|
||||
setCredential: (apiKey: SecretInput, mode?: SecretInputMode) => void | Promise<void>;
|
||||
defaultModel: string;
|
||||
applyDefaultConfig: ApiKeyProviderConfigApplier;
|
||||
applyProviderConfig: ApiKeyProviderConfigApplier;
|
||||
noteMessage?: string;
|
||||
noteTitle?: string;
|
||||
tokenProvider?: string;
|
||||
normalize?: (value: string) => string;
|
||||
validate?: (value: string) => string | undefined;
|
||||
noteDefault?: string;
|
||||
}): Promise<ApplyAuthChoiceResult> {
|
||||
let nextConfig = config;
|
||||
|
||||
await ensureApiKeyFromOptionEnvOrPrompt({
|
||||
token: params.opts?.token,
|
||||
provider,
|
||||
tokenProvider,
|
||||
secretInputMode: requestedSecretInputMode,
|
||||
config: nextConfig,
|
||||
expectedProviders,
|
||||
envLabel,
|
||||
promptMessage,
|
||||
setCredential: async (apiKey, mode) => {
|
||||
await setCredential(apiKey, mode);
|
||||
},
|
||||
noteMessage,
|
||||
noteTitle,
|
||||
normalize,
|
||||
validate,
|
||||
prompter: params.prompter,
|
||||
});
|
||||
|
||||
nextConfig = applyAuthProfileConfig(nextConfig, {
|
||||
profileId,
|
||||
provider,
|
||||
mode: "api_key",
|
||||
});
|
||||
setConfig(nextConfig);
|
||||
await applyProviderDefaultModel({
|
||||
defaultModel,
|
||||
applyDefaultConfig,
|
||||
applyProviderConfig,
|
||||
noteDefault,
|
||||
});
|
||||
|
||||
return { config: getConfig(), agentModelOverride: getAgentModelOverride() };
|
||||
}
|
||||
|
||||
export async function applyLiteLlmApiKeyProvider({
|
||||
params,
|
||||
authChoice,
|
||||
config,
|
||||
setConfig,
|
||||
getConfig,
|
||||
normalizedTokenProvider,
|
||||
requestedSecretInputMode,
|
||||
applyProviderDefaultModel,
|
||||
getAgentModelOverride,
|
||||
}: ApplyApiKeyProviderParams): Promise<ApplyAuthChoiceResult | null> {
|
||||
if (authChoice !== "litellm-api-key") {
|
||||
return null;
|
||||
}
|
||||
|
||||
let nextConfig = config;
|
||||
const store = ensureAuthProfileStore(params.agentDir, { allowKeychainPrompt: false });
|
||||
const profileOrder = resolveAuthProfileOrder({ cfg: nextConfig, store, provider: "litellm" });
|
||||
const existingProfileId = profileOrder.find((profileId) => Boolean(store.profiles[profileId]));
|
||||
const existingCred = existingProfileId ? store.profiles[existingProfileId] : undefined;
|
||||
let profileId = "litellm:default";
|
||||
let hasCredential = Boolean(existingProfileId && existingCred?.type === "api_key");
|
||||
if (hasCredential && existingProfileId) {
|
||||
profileId = existingProfileId;
|
||||
}
|
||||
|
||||
if (!hasCredential) {
|
||||
await ensureApiKeyFromOptionEnvOrPrompt({
|
||||
token: params.opts?.token,
|
||||
tokenProvider: normalizedTokenProvider,
|
||||
secretInputMode: requestedSecretInputMode,
|
||||
config: nextConfig,
|
||||
expectedProviders: ["litellm"],
|
||||
provider: "litellm",
|
||||
envLabel: "LITELLM_API_KEY",
|
||||
promptMessage: "Enter LiteLLM API key",
|
||||
normalize: normalizeApiKeyInput,
|
||||
validate: validateApiKeyInput,
|
||||
prompter: params.prompter,
|
||||
setCredential: async (apiKey, mode) =>
|
||||
setLitellmApiKey(apiKey, params.agentDir, { secretInputMode: mode }),
|
||||
noteMessage:
|
||||
"LiteLLM provides a unified API to 100+ LLM providers.\nGet your API key from your LiteLLM proxy or https://litellm.ai\nDefault proxy runs on http://localhost:4000",
|
||||
noteTitle: "LiteLLM",
|
||||
});
|
||||
hasCredential = true;
|
||||
}
|
||||
|
||||
if (hasCredential) {
|
||||
nextConfig = applyAuthProfileConfig(nextConfig, {
|
||||
profileId,
|
||||
provider: "litellm",
|
||||
mode: "api_key",
|
||||
});
|
||||
}
|
||||
setConfig(nextConfig);
|
||||
await applyProviderDefaultModel({
|
||||
defaultModel: LITELLM_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applyLitellmConfig,
|
||||
applyProviderConfig: applyLitellmProviderConfig,
|
||||
noteDefault: LITELLM_DEFAULT_MODEL_REF,
|
||||
});
|
||||
return { config: getConfig(), agentModelOverride: getAgentModelOverride() };
|
||||
}
|
||||
|
||||
export async function applySimpleAuthChoiceApiProvider({
|
||||
params,
|
||||
authChoice,
|
||||
config,
|
||||
setConfig,
|
||||
getConfig,
|
||||
normalizedTokenProvider,
|
||||
requestedSecretInputMode,
|
||||
applyProviderDefaultModel,
|
||||
getAgentModelOverride,
|
||||
}: ApplyApiKeyProviderParams): Promise<ApplyAuthChoiceResult | null> {
|
||||
const simpleApiKeyProviderFlow = SIMPLE_API_KEY_PROVIDER_FLOWS[authChoice];
|
||||
if (!simpleApiKeyProviderFlow) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await applyApiKeyProviderWithDefaultModel({
|
||||
params,
|
||||
authChoice,
|
||||
config,
|
||||
setConfig,
|
||||
getConfig,
|
||||
normalizedTokenProvider,
|
||||
requestedSecretInputMode,
|
||||
applyProviderDefaultModel,
|
||||
getAgentModelOverride,
|
||||
provider: simpleApiKeyProviderFlow.provider,
|
||||
profileId: simpleApiKeyProviderFlow.profileId,
|
||||
expectedProviders: simpleApiKeyProviderFlow.expectedProviders,
|
||||
envLabel: simpleApiKeyProviderFlow.envLabel,
|
||||
promptMessage: simpleApiKeyProviderFlow.promptMessage,
|
||||
setCredential: async (apiKey, mode) =>
|
||||
simpleApiKeyProviderFlow.setCredential(apiKey, params.agentDir, {
|
||||
secretInputMode: mode ?? requestedSecretInputMode,
|
||||
}),
|
||||
defaultModel: simpleApiKeyProviderFlow.defaultModel,
|
||||
applyDefaultConfig: simpleApiKeyProviderFlow.applyDefaultConfig,
|
||||
applyProviderConfig: simpleApiKeyProviderFlow.applyProviderConfig,
|
||||
noteDefault: simpleApiKeyProviderFlow.noteDefault,
|
||||
noteMessage: simpleApiKeyProviderFlow.noteMessage,
|
||||
noteTitle: simpleApiKeyProviderFlow.noteTitle,
|
||||
tokenProvider: simpleApiKeyProviderFlow.tokenProvider,
|
||||
normalize: simpleApiKeyProviderFlow.normalize,
|
||||
validate: simpleApiKeyProviderFlow.validate,
|
||||
});
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
import { ensureAuthProfileStore, resolveAuthProfileOrder } from "../agents/auth-profiles.js";
|
||||
import type { SecretInput } from "../config/types.secrets.js";
|
||||
import { normalizeApiKeyInput, validateApiKeyInput } from "./auth-choice.api-key.js";
|
||||
import {
|
||||
normalizeSecretInputModeInput,
|
||||
@@ -8,6 +6,10 @@ import {
|
||||
ensureApiKeyFromOptionEnvOrPrompt,
|
||||
normalizeTokenProviderInput,
|
||||
} from "./auth-choice.apply-helpers.js";
|
||||
import {
|
||||
applyLiteLlmApiKeyProvider,
|
||||
applySimpleAuthChoiceApiProvider,
|
||||
} from "./auth-choice.apply.api-key-providers.js";
|
||||
import { applyAuthChoiceHuggingface } from "./auth-choice.apply.huggingface.js";
|
||||
import type { ApplyAuthChoiceParams, ApplyAuthChoiceResult } from "./auth-choice.apply.js";
|
||||
import { applyAuthChoiceOpenRouter } from "./auth-choice.apply.openrouter.js";
|
||||
@@ -15,80 +17,19 @@ import {
|
||||
applyGoogleGeminiModelDefault,
|
||||
GOOGLE_GEMINI_DEFAULT_MODEL,
|
||||
} from "./google-gemini-model-default.js";
|
||||
import type { ApiKeyStorageOptions } from "./onboard-auth.credentials.js";
|
||||
import {
|
||||
applyAuthProfileConfig,
|
||||
applyCloudflareAiGatewayConfig,
|
||||
applyCloudflareAiGatewayProviderConfig,
|
||||
applyKilocodeConfig,
|
||||
applyKilocodeProviderConfig,
|
||||
applyQianfanConfig,
|
||||
applyQianfanProviderConfig,
|
||||
applyKimiCodeConfig,
|
||||
applyKimiCodeProviderConfig,
|
||||
applyLitellmConfig,
|
||||
applyLitellmProviderConfig,
|
||||
applyMistralConfig,
|
||||
applyMistralProviderConfig,
|
||||
applyMoonshotConfig,
|
||||
applyMoonshotConfigCn,
|
||||
applyMoonshotProviderConfig,
|
||||
applyMoonshotProviderConfigCn,
|
||||
applyOpencodeGoConfig,
|
||||
applyOpencodeGoProviderConfig,
|
||||
applyOpencodeZenConfig,
|
||||
applyOpencodeZenProviderConfig,
|
||||
applySyntheticConfig,
|
||||
applySyntheticProviderConfig,
|
||||
applyTogetherConfig,
|
||||
applyTogetherProviderConfig,
|
||||
applyVeniceConfig,
|
||||
applyVeniceProviderConfig,
|
||||
applyVercelAiGatewayConfig,
|
||||
applyVercelAiGatewayProviderConfig,
|
||||
applyXiaomiConfig,
|
||||
applyXiaomiProviderConfig,
|
||||
applyZaiConfig,
|
||||
applyZaiProviderConfig,
|
||||
CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_REF,
|
||||
KILOCODE_DEFAULT_MODEL_REF,
|
||||
LITELLM_DEFAULT_MODEL_REF,
|
||||
QIANFAN_DEFAULT_MODEL_REF,
|
||||
KIMI_CODING_MODEL_REF,
|
||||
MOONSHOT_DEFAULT_MODEL_REF,
|
||||
MISTRAL_DEFAULT_MODEL_REF,
|
||||
SYNTHETIC_DEFAULT_MODEL_REF,
|
||||
TOGETHER_DEFAULT_MODEL_REF,
|
||||
VENICE_DEFAULT_MODEL_REF,
|
||||
VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF,
|
||||
XIAOMI_DEFAULT_MODEL_REF,
|
||||
setCloudflareAiGatewayConfig,
|
||||
setQianfanApiKey,
|
||||
setGeminiApiKey,
|
||||
setKilocodeApiKey,
|
||||
setLitellmApiKey,
|
||||
setKimiCodingApiKey,
|
||||
setMistralApiKey,
|
||||
setMoonshotApiKey,
|
||||
setOpencodeGoApiKey,
|
||||
setOpencodeZenApiKey,
|
||||
setSyntheticApiKey,
|
||||
setTogetherApiKey,
|
||||
setVeniceApiKey,
|
||||
setVercelAiGatewayApiKey,
|
||||
setXiaomiApiKey,
|
||||
setZaiApiKey,
|
||||
ZAI_DEFAULT_MODEL_REF,
|
||||
MODELSTUDIO_DEFAULT_MODEL_REF,
|
||||
applyModelStudioConfig,
|
||||
applyModelStudioConfigCn,
|
||||
applyModelStudioProviderConfig,
|
||||
applyModelStudioProviderConfigCn,
|
||||
setModelStudioApiKey,
|
||||
} from "./onboard-auth.js";
|
||||
import type { AuthChoice, SecretInputMode } from "./onboard-types.js";
|
||||
import { OPENCODE_GO_DEFAULT_MODEL_REF } from "./opencode-go-model-default.js";
|
||||
import { OPENCODE_ZEN_DEFAULT_MODEL } from "./opencode-zen-model-default.js";
|
||||
import type { AuthChoice } from "./onboard-types.js";
|
||||
import { detectZaiEndpoint } from "./zai-endpoint-detect.js";
|
||||
|
||||
const API_KEY_TOKEN_PROVIDER_AUTH_CHOICE: Record<string, AuthChoice> = {
|
||||
@@ -122,265 +63,6 @@ const ZAI_AUTH_CHOICE_ENDPOINT: Partial<
|
||||
"zai-cn": "cn",
|
||||
};
|
||||
|
||||
type ApiKeyProviderConfigApplier = (
|
||||
config: ApplyAuthChoiceParams["config"],
|
||||
) => ApplyAuthChoiceParams["config"];
|
||||
|
||||
type SimpleApiKeyProviderFlow = {
|
||||
provider: Parameters<typeof ensureApiKeyFromOptionEnvOrPrompt>[0]["provider"];
|
||||
profileId: string;
|
||||
expectedProviders: string[];
|
||||
envLabel: string;
|
||||
promptMessage: string;
|
||||
setCredential: (
|
||||
apiKey: SecretInput,
|
||||
agentDir?: string,
|
||||
options?: ApiKeyStorageOptions,
|
||||
) => void | Promise<void>;
|
||||
defaultModel: string;
|
||||
applyDefaultConfig: ApiKeyProviderConfigApplier;
|
||||
applyProviderConfig: ApiKeyProviderConfigApplier;
|
||||
tokenProvider?: string;
|
||||
normalize?: (value: string) => string;
|
||||
validate?: (value: string) => string | undefined;
|
||||
noteDefault?: string;
|
||||
noteMessage?: string;
|
||||
noteTitle?: string;
|
||||
};
|
||||
|
||||
const SIMPLE_API_KEY_PROVIDER_FLOWS: Partial<Record<AuthChoice, SimpleApiKeyProviderFlow>> = {
|
||||
"ai-gateway-api-key": {
|
||||
provider: "vercel-ai-gateway",
|
||||
profileId: "vercel-ai-gateway:default",
|
||||
expectedProviders: ["vercel-ai-gateway"],
|
||||
envLabel: "AI_GATEWAY_API_KEY",
|
||||
promptMessage: "Enter Vercel AI Gateway API key",
|
||||
setCredential: setVercelAiGatewayApiKey,
|
||||
defaultModel: VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applyVercelAiGatewayConfig,
|
||||
applyProviderConfig: applyVercelAiGatewayProviderConfig,
|
||||
noteDefault: VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF,
|
||||
},
|
||||
"moonshot-api-key": {
|
||||
provider: "moonshot",
|
||||
profileId: "moonshot:default",
|
||||
expectedProviders: ["moonshot"],
|
||||
envLabel: "MOONSHOT_API_KEY",
|
||||
promptMessage: "Enter Moonshot API key",
|
||||
setCredential: setMoonshotApiKey,
|
||||
defaultModel: MOONSHOT_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applyMoonshotConfig,
|
||||
applyProviderConfig: applyMoonshotProviderConfig,
|
||||
},
|
||||
"moonshot-api-key-cn": {
|
||||
provider: "moonshot",
|
||||
profileId: "moonshot:default",
|
||||
expectedProviders: ["moonshot"],
|
||||
envLabel: "MOONSHOT_API_KEY",
|
||||
promptMessage: "Enter Moonshot API key (.cn)",
|
||||
setCredential: setMoonshotApiKey,
|
||||
defaultModel: MOONSHOT_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applyMoonshotConfigCn,
|
||||
applyProviderConfig: applyMoonshotProviderConfigCn,
|
||||
},
|
||||
"kimi-code-api-key": {
|
||||
provider: "kimi-coding",
|
||||
profileId: "kimi-coding:default",
|
||||
expectedProviders: ["kimi-code", "kimi-coding"],
|
||||
envLabel: "KIMI_API_KEY",
|
||||
promptMessage: "Enter Kimi Coding API key",
|
||||
setCredential: setKimiCodingApiKey,
|
||||
defaultModel: KIMI_CODING_MODEL_REF,
|
||||
applyDefaultConfig: applyKimiCodeConfig,
|
||||
applyProviderConfig: applyKimiCodeProviderConfig,
|
||||
noteDefault: KIMI_CODING_MODEL_REF,
|
||||
noteMessage: [
|
||||
"Kimi Coding uses a dedicated endpoint and API key.",
|
||||
"Get your API key at: https://www.kimi.com/code/en",
|
||||
].join("\n"),
|
||||
noteTitle: "Kimi Coding",
|
||||
},
|
||||
"xiaomi-api-key": {
|
||||
provider: "xiaomi",
|
||||
profileId: "xiaomi:default",
|
||||
expectedProviders: ["xiaomi"],
|
||||
envLabel: "XIAOMI_API_KEY",
|
||||
promptMessage: "Enter Xiaomi API key",
|
||||
setCredential: setXiaomiApiKey,
|
||||
defaultModel: XIAOMI_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applyXiaomiConfig,
|
||||
applyProviderConfig: applyXiaomiProviderConfig,
|
||||
noteDefault: XIAOMI_DEFAULT_MODEL_REF,
|
||||
},
|
||||
"mistral-api-key": {
|
||||
provider: "mistral",
|
||||
profileId: "mistral:default",
|
||||
expectedProviders: ["mistral"],
|
||||
envLabel: "MISTRAL_API_KEY",
|
||||
promptMessage: "Enter Mistral API key",
|
||||
setCredential: setMistralApiKey,
|
||||
defaultModel: MISTRAL_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applyMistralConfig,
|
||||
applyProviderConfig: applyMistralProviderConfig,
|
||||
noteDefault: MISTRAL_DEFAULT_MODEL_REF,
|
||||
},
|
||||
"venice-api-key": {
|
||||
provider: "venice",
|
||||
profileId: "venice:default",
|
||||
expectedProviders: ["venice"],
|
||||
envLabel: "VENICE_API_KEY",
|
||||
promptMessage: "Enter Venice AI API key",
|
||||
setCredential: setVeniceApiKey,
|
||||
defaultModel: VENICE_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applyVeniceConfig,
|
||||
applyProviderConfig: applyVeniceProviderConfig,
|
||||
noteDefault: VENICE_DEFAULT_MODEL_REF,
|
||||
noteMessage: [
|
||||
"Venice AI provides privacy-focused inference with uncensored models.",
|
||||
"Get your API key at: https://venice.ai/settings/api",
|
||||
"Supports 'private' (fully private) and 'anonymized' (proxy) modes.",
|
||||
].join("\n"),
|
||||
noteTitle: "Venice AI",
|
||||
},
|
||||
"opencode-zen": {
|
||||
provider: "opencode",
|
||||
profileId: "opencode:default",
|
||||
expectedProviders: ["opencode", "opencode-go"],
|
||||
envLabel: "OPENCODE_API_KEY",
|
||||
promptMessage: "Enter OpenCode API key",
|
||||
setCredential: setOpencodeZenApiKey,
|
||||
defaultModel: OPENCODE_ZEN_DEFAULT_MODEL,
|
||||
applyDefaultConfig: applyOpencodeZenConfig,
|
||||
applyProviderConfig: applyOpencodeZenProviderConfig,
|
||||
noteDefault: OPENCODE_ZEN_DEFAULT_MODEL,
|
||||
noteMessage: [
|
||||
"OpenCode uses one API key across the Zen and Go catalogs.",
|
||||
"Zen provides access to Claude, GPT, Gemini, and more models.",
|
||||
"Get your API key at: https://opencode.ai/auth",
|
||||
"Choose the Zen catalog when you want the curated multi-model proxy.",
|
||||
].join("\n"),
|
||||
noteTitle: "OpenCode",
|
||||
},
|
||||
"opencode-go": {
|
||||
provider: "opencode-go",
|
||||
profileId: "opencode-go:default",
|
||||
expectedProviders: ["opencode", "opencode-go"],
|
||||
envLabel: "OPENCODE_API_KEY",
|
||||
promptMessage: "Enter OpenCode API key",
|
||||
setCredential: setOpencodeGoApiKey,
|
||||
defaultModel: OPENCODE_GO_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applyOpencodeGoConfig,
|
||||
applyProviderConfig: applyOpencodeGoProviderConfig,
|
||||
noteDefault: OPENCODE_GO_DEFAULT_MODEL_REF,
|
||||
noteMessage: [
|
||||
"OpenCode uses one API key across the Zen and Go catalogs.",
|
||||
"Go provides access to Kimi, GLM, and MiniMax models through the Go catalog.",
|
||||
"Get your API key at: https://opencode.ai/auth",
|
||||
"Choose the Go catalog when you want the OpenCode-hosted Kimi/GLM/MiniMax lineup.",
|
||||
].join("\n"),
|
||||
noteTitle: "OpenCode",
|
||||
},
|
||||
"together-api-key": {
|
||||
provider: "together",
|
||||
profileId: "together:default",
|
||||
expectedProviders: ["together"],
|
||||
envLabel: "TOGETHER_API_KEY",
|
||||
promptMessage: "Enter Together AI API key",
|
||||
setCredential: setTogetherApiKey,
|
||||
defaultModel: TOGETHER_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applyTogetherConfig,
|
||||
applyProviderConfig: applyTogetherProviderConfig,
|
||||
noteDefault: TOGETHER_DEFAULT_MODEL_REF,
|
||||
noteMessage: [
|
||||
"Together AI provides access to leading open-source models including Llama, DeepSeek, Qwen, and more.",
|
||||
"Get your API key at: https://api.together.xyz/settings/api-keys",
|
||||
].join("\n"),
|
||||
noteTitle: "Together AI",
|
||||
},
|
||||
"qianfan-api-key": {
|
||||
provider: "qianfan",
|
||||
profileId: "qianfan:default",
|
||||
expectedProviders: ["qianfan"],
|
||||
envLabel: "QIANFAN_API_KEY",
|
||||
promptMessage: "Enter QIANFAN API key",
|
||||
setCredential: setQianfanApiKey,
|
||||
defaultModel: QIANFAN_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applyQianfanConfig,
|
||||
applyProviderConfig: applyQianfanProviderConfig,
|
||||
noteDefault: QIANFAN_DEFAULT_MODEL_REF,
|
||||
noteMessage: [
|
||||
"Get your API key at: https://console.bce.baidu.com/qianfan/ais/console/apiKey",
|
||||
"API key format: bce-v3/ALTAK-...",
|
||||
].join("\n"),
|
||||
noteTitle: "QIANFAN",
|
||||
},
|
||||
"kilocode-api-key": {
|
||||
provider: "kilocode",
|
||||
profileId: "kilocode:default",
|
||||
expectedProviders: ["kilocode"],
|
||||
envLabel: "KILOCODE_API_KEY",
|
||||
promptMessage: "Enter Kilo Gateway API key",
|
||||
setCredential: setKilocodeApiKey,
|
||||
defaultModel: KILOCODE_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applyKilocodeConfig,
|
||||
applyProviderConfig: applyKilocodeProviderConfig,
|
||||
noteDefault: KILOCODE_DEFAULT_MODEL_REF,
|
||||
},
|
||||
"modelstudio-api-key-cn": {
|
||||
provider: "modelstudio",
|
||||
profileId: "modelstudio:default",
|
||||
expectedProviders: ["modelstudio"],
|
||||
envLabel: "MODELSTUDIO_API_KEY",
|
||||
promptMessage: "Enter Alibaba Cloud Model Studio Coding Plan API key (China)",
|
||||
setCredential: setModelStudioApiKey,
|
||||
defaultModel: MODELSTUDIO_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applyModelStudioConfigCn,
|
||||
applyProviderConfig: applyModelStudioProviderConfigCn,
|
||||
noteDefault: MODELSTUDIO_DEFAULT_MODEL_REF,
|
||||
noteMessage: [
|
||||
"Get your API key at: https://bailian.console.aliyun.com/",
|
||||
"Endpoint: coding.dashscope.aliyuncs.com",
|
||||
"Models: qwen3.5-plus, glm-4.7, kimi-k2.5, MiniMax-M2.5, etc.",
|
||||
].join("\n"),
|
||||
noteTitle: "Alibaba Cloud Model Studio Coding Plan (China)",
|
||||
normalize: (value) => String(value ?? "").trim(),
|
||||
validate: (value) => (String(value ?? "").trim() ? undefined : "Required"),
|
||||
},
|
||||
"modelstudio-api-key": {
|
||||
provider: "modelstudio",
|
||||
profileId: "modelstudio:default",
|
||||
expectedProviders: ["modelstudio"],
|
||||
envLabel: "MODELSTUDIO_API_KEY",
|
||||
promptMessage: "Enter Alibaba Cloud Model Studio Coding Plan API key (Global/Intl)",
|
||||
setCredential: setModelStudioApiKey,
|
||||
defaultModel: MODELSTUDIO_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applyModelStudioConfig,
|
||||
applyProviderConfig: applyModelStudioProviderConfig,
|
||||
noteDefault: MODELSTUDIO_DEFAULT_MODEL_REF,
|
||||
noteMessage: [
|
||||
"Get your API key at: https://bailian.console.aliyun.com/",
|
||||
"Endpoint: coding-intl.dashscope.aliyuncs.com",
|
||||
"Models: qwen3.5-plus, glm-4.7, kimi-k2.5, MiniMax-M2.5, etc.",
|
||||
].join("\n"),
|
||||
noteTitle: "Alibaba Cloud Model Studio Coding Plan (Global/Intl)",
|
||||
normalize: (value) => String(value ?? "").trim(),
|
||||
validate: (value) => (String(value ?? "").trim() ? undefined : "Required"),
|
||||
},
|
||||
"synthetic-api-key": {
|
||||
provider: "synthetic",
|
||||
profileId: "synthetic:default",
|
||||
expectedProviders: ["synthetic"],
|
||||
envLabel: "SYNTHETIC_API_KEY",
|
||||
promptMessage: "Enter Synthetic API key",
|
||||
setCredential: setSyntheticApiKey,
|
||||
defaultModel: SYNTHETIC_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applySyntheticConfig,
|
||||
applyProviderConfig: applySyntheticProviderConfig,
|
||||
normalize: (value) => String(value ?? "").trim(),
|
||||
validate: (value) => (String(value ?? "").trim() ? undefined : "Required"),
|
||||
},
|
||||
};
|
||||
|
||||
export async function applyAuthChoiceApiProviders(
|
||||
params: ApplyAuthChoiceParams,
|
||||
): Promise<ApplyAuthChoiceResult | null> {
|
||||
@@ -404,152 +86,38 @@ export async function applyAuthChoiceApiProviders(
|
||||
}
|
||||
}
|
||||
|
||||
async function applyApiKeyProviderWithDefaultModel({
|
||||
provider,
|
||||
profileId,
|
||||
expectedProviders,
|
||||
envLabel,
|
||||
promptMessage,
|
||||
setCredential,
|
||||
defaultModel,
|
||||
applyDefaultConfig,
|
||||
applyProviderConfig,
|
||||
noteMessage,
|
||||
noteTitle,
|
||||
tokenProvider = normalizedTokenProvider,
|
||||
normalize = normalizeApiKeyInput,
|
||||
validate = validateApiKeyInput,
|
||||
noteDefault = defaultModel,
|
||||
}: {
|
||||
provider: Parameters<typeof ensureApiKeyFromOptionEnvOrPrompt>[0]["provider"];
|
||||
profileId: string;
|
||||
expectedProviders: string[];
|
||||
envLabel: string;
|
||||
promptMessage: string;
|
||||
setCredential: (apiKey: SecretInput, mode?: SecretInputMode) => void | Promise<void>;
|
||||
defaultModel: string;
|
||||
applyDefaultConfig: (
|
||||
config: ApplyAuthChoiceParams["config"],
|
||||
) => ApplyAuthChoiceParams["config"];
|
||||
applyProviderConfig: (
|
||||
config: ApplyAuthChoiceParams["config"],
|
||||
) => ApplyAuthChoiceParams["config"];
|
||||
noteMessage?: string;
|
||||
noteTitle?: string;
|
||||
tokenProvider?: string;
|
||||
normalize?: (value: string) => string;
|
||||
validate?: (value: string) => string | undefined;
|
||||
noteDefault?: string;
|
||||
}): Promise<ApplyAuthChoiceResult> {
|
||||
await ensureApiKeyFromOptionEnvOrPrompt({
|
||||
token: params.opts?.token,
|
||||
provider,
|
||||
tokenProvider,
|
||||
secretInputMode: requestedSecretInputMode,
|
||||
config: nextConfig,
|
||||
expectedProviders,
|
||||
envLabel,
|
||||
promptMessage,
|
||||
setCredential: async (apiKey, mode) => {
|
||||
await setCredential(apiKey, mode);
|
||||
},
|
||||
noteMessage,
|
||||
noteTitle,
|
||||
normalize,
|
||||
validate,
|
||||
prompter: params.prompter,
|
||||
});
|
||||
|
||||
nextConfig = applyAuthProfileConfig(nextConfig, {
|
||||
profileId,
|
||||
provider,
|
||||
mode: "api_key",
|
||||
});
|
||||
await applyProviderDefaultModel({
|
||||
defaultModel,
|
||||
applyDefaultConfig,
|
||||
applyProviderConfig,
|
||||
noteDefault,
|
||||
});
|
||||
|
||||
return { config: nextConfig, agentModelOverride };
|
||||
}
|
||||
|
||||
if (authChoice === "openrouter-api-key") {
|
||||
return applyAuthChoiceOpenRouter(params);
|
||||
}
|
||||
|
||||
if (authChoice === "litellm-api-key") {
|
||||
const store = ensureAuthProfileStore(params.agentDir, { allowKeychainPrompt: false });
|
||||
const profileOrder = resolveAuthProfileOrder({ cfg: nextConfig, store, provider: "litellm" });
|
||||
const existingProfileId = profileOrder.find((profileId) => Boolean(store.profiles[profileId]));
|
||||
const existingCred = existingProfileId ? store.profiles[existingProfileId] : undefined;
|
||||
let profileId = "litellm:default";
|
||||
let hasCredential = Boolean(existingProfileId && existingCred?.type === "api_key");
|
||||
if (hasCredential && existingProfileId) {
|
||||
profileId = existingProfileId;
|
||||
}
|
||||
|
||||
if (!hasCredential) {
|
||||
await ensureApiKeyFromOptionEnvOrPrompt({
|
||||
token: params.opts?.token,
|
||||
tokenProvider: normalizedTokenProvider,
|
||||
secretInputMode: requestedSecretInputMode,
|
||||
config: nextConfig,
|
||||
expectedProviders: ["litellm"],
|
||||
provider: "litellm",
|
||||
envLabel: "LITELLM_API_KEY",
|
||||
promptMessage: "Enter LiteLLM API key",
|
||||
normalize: normalizeApiKeyInput,
|
||||
validate: validateApiKeyInput,
|
||||
prompter: params.prompter,
|
||||
setCredential: async (apiKey, mode) =>
|
||||
setLitellmApiKey(apiKey, params.agentDir, { secretInputMode: mode }),
|
||||
noteMessage:
|
||||
"LiteLLM provides a unified API to 100+ LLM providers.\nGet your API key from your LiteLLM proxy or https://litellm.ai\nDefault proxy runs on http://localhost:4000",
|
||||
noteTitle: "LiteLLM",
|
||||
});
|
||||
hasCredential = true;
|
||||
}
|
||||
|
||||
if (hasCredential) {
|
||||
nextConfig = applyAuthProfileConfig(nextConfig, {
|
||||
profileId,
|
||||
provider: "litellm",
|
||||
mode: "api_key",
|
||||
});
|
||||
}
|
||||
await applyProviderDefaultModel({
|
||||
defaultModel: LITELLM_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applyLitellmConfig,
|
||||
applyProviderConfig: applyLitellmProviderConfig,
|
||||
noteDefault: LITELLM_DEFAULT_MODEL_REF,
|
||||
});
|
||||
return { config: nextConfig, agentModelOverride };
|
||||
const litellmResult = await applyLiteLlmApiKeyProvider({
|
||||
params,
|
||||
authChoice,
|
||||
config: nextConfig,
|
||||
setConfig: (config) => (nextConfig = config),
|
||||
getConfig: () => nextConfig,
|
||||
normalizedTokenProvider,
|
||||
requestedSecretInputMode,
|
||||
applyProviderDefaultModel,
|
||||
getAgentModelOverride: () => agentModelOverride,
|
||||
});
|
||||
if (litellmResult) {
|
||||
return litellmResult;
|
||||
}
|
||||
|
||||
const simpleApiKeyProviderFlow = SIMPLE_API_KEY_PROVIDER_FLOWS[authChoice];
|
||||
if (simpleApiKeyProviderFlow) {
|
||||
return await applyApiKeyProviderWithDefaultModel({
|
||||
provider: simpleApiKeyProviderFlow.provider,
|
||||
profileId: simpleApiKeyProviderFlow.profileId,
|
||||
expectedProviders: simpleApiKeyProviderFlow.expectedProviders,
|
||||
envLabel: simpleApiKeyProviderFlow.envLabel,
|
||||
promptMessage: simpleApiKeyProviderFlow.promptMessage,
|
||||
setCredential: async (apiKey, mode) =>
|
||||
simpleApiKeyProviderFlow.setCredential(apiKey, params.agentDir, {
|
||||
secretInputMode: mode ?? requestedSecretInputMode,
|
||||
}),
|
||||
defaultModel: simpleApiKeyProviderFlow.defaultModel,
|
||||
applyDefaultConfig: simpleApiKeyProviderFlow.applyDefaultConfig,
|
||||
applyProviderConfig: simpleApiKeyProviderFlow.applyProviderConfig,
|
||||
noteDefault: simpleApiKeyProviderFlow.noteDefault,
|
||||
noteMessage: simpleApiKeyProviderFlow.noteMessage,
|
||||
noteTitle: simpleApiKeyProviderFlow.noteTitle,
|
||||
tokenProvider: simpleApiKeyProviderFlow.tokenProvider,
|
||||
normalize: simpleApiKeyProviderFlow.normalize,
|
||||
validate: simpleApiKeyProviderFlow.validate,
|
||||
});
|
||||
const simpleProviderResult = await applySimpleAuthChoiceApiProvider({
|
||||
params,
|
||||
authChoice,
|
||||
config: nextConfig,
|
||||
setConfig: (config) => (nextConfig = config),
|
||||
getConfig: () => nextConfig,
|
||||
normalizedTokenProvider,
|
||||
requestedSecretInputMode,
|
||||
applyProviderDefaultModel,
|
||||
getAgentModelOverride: () => agentModelOverride,
|
||||
});
|
||||
if (simpleProviderResult) {
|
||||
return simpleProviderResult;
|
||||
}
|
||||
|
||||
if (authChoice === "cloudflare-ai-gateway-api-key") {
|
||||
|
||||
Reference in New Issue
Block a user