fix(litellm): honor CLI flags during onboarding

Add support for --litellm-api-key, --litellm-base-url, and
--litellm-model CLI flags to enable non-interactive/automation
use cases for LiteLLM provider onboarding.

Co-Authored-By: Claude (claude-opus-4-5) <noreply@anthropic.com>
This commit is contained in:
Charles-Henri ROBICHE 2026-01-27 10:08:47 +01:00
parent efd827b526
commit f30e9c466f
No known key found for this signature in database
3 changed files with 53 additions and 27 deletions

View File

@ -588,7 +588,12 @@ export async function applyAuthChoiceApiProviders(
let hasCredential = false; let hasCredential = false;
let apiKey: string | undefined; let apiKey: string | undefined;
// Check for pre-provided credentials via CLI options // Check for pre-provided API key via CLI options (--litellm-api-key or --token with --token-provider litellm)
if (!hasCredential && params.opts?.litellmApiKey) {
apiKey = normalizeApiKeyInput(params.opts.litellmApiKey);
await setLitellmApiKey(apiKey, params.agentDir);
hasCredential = true;
}
if (!hasCredential && params.opts?.token && params.opts?.tokenProvider === "litellm") { if (!hasCredential && params.opts?.token && params.opts?.tokenProvider === "litellm") {
apiKey = normalizeApiKeyInput(params.opts.token); apiKey = normalizeApiKeyInput(params.opts.token);
await setLitellmApiKey(apiKey, params.agentDir); await setLitellmApiKey(apiKey, params.agentDir);
@ -610,7 +615,7 @@ export async function applyAuthChoiceApiProviders(
// Check for existing env key // Check for existing env key
const envKey = resolveEnvApiKey("litellm"); const envKey = resolveEnvApiKey("litellm");
if (envKey) { if (!hasCredential && envKey) {
const useExisting = await params.prompter.confirm({ const useExisting = await params.prompter.confirm({
message: `Use existing LITELLM_API_KEY (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`, message: `Use existing LITELLM_API_KEY (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`,
initialValue: true, initialValue: true,
@ -631,24 +636,28 @@ export async function applyAuthChoiceApiProviders(
await setLitellmApiKey(apiKey, params.agentDir); await setLitellmApiKey(apiKey, params.agentDir);
} }
// Prompt for base URL // Check for pre-provided base URL via CLI option (--litellm-base-url)
const defaultBaseUrl = process.env.LITELLM_BASE_URL ?? "http://localhost:4000"; let normalizedBaseUrl: string;
const baseUrl = await params.prompter.text({ if (params.opts?.litellmBaseUrl) {
message: "Enter LiteLLM base URL", normalizedBaseUrl = params.opts.litellmBaseUrl.trim();
initialValue: defaultBaseUrl, } else {
placeholder: defaultBaseUrl, const defaultBaseUrl = process.env.LITELLM_BASE_URL ?? "http://localhost:4000";
validate: (value) => { const baseUrl = await params.prompter.text({
if (!value?.trim()) return "Base URL is required"; message: "Enter LiteLLM base URL",
try { initialValue: defaultBaseUrl,
new URL(value); placeholder: defaultBaseUrl,
return undefined; validate: (value) => {
} catch { if (!value?.trim()) return "Base URL is required";
return "Invalid URL format"; try {
} new URL(value);
}, return undefined;
}); } catch {
return "Invalid URL format";
const normalizedBaseUrl = String(baseUrl).trim(); }
},
});
normalizedBaseUrl = String(baseUrl).trim();
}
// Try to fetch available models from LiteLLM // Try to fetch available models from LiteLLM
type LitellmModelInfo = { id: string; maxInputTokens?: number; maxOutputTokens?: number }; type LitellmModelInfo = { id: string; maxInputTokens?: number; maxOutputTokens?: number };
@ -722,7 +731,18 @@ export async function applyAuthChoiceApiProviders(
let contextWindow: number | undefined; let contextWindow: number | undefined;
let maxTokens: number | undefined; let maxTokens: number | undefined;
if (availableModels.length > 0) { // Check for pre-provided model via CLI option (--litellm-model)
if (params.opts?.litellmModel) {
normalizedModelId = params.opts.litellmModel.trim();
// Try to get context info from model info map
const modelInfo = availableModels.find((m) => m.id === normalizedModelId);
if (modelInfo?.maxInputTokens) {
contextWindow = modelInfo.maxInputTokens;
}
if (modelInfo?.maxOutputTokens) {
maxTokens = modelInfo.maxOutputTokens;
}
} else if (availableModels.length > 0) {
// Let user select from available models // Let user select from available models
type SelectOption = { value: string; label: string; hint?: string }; type SelectOption = { value: string; label: string; hint?: string };
const modelOptions: SelectOption[] = availableModels.map((m) => ({ const modelOptions: SelectOption[] = availableModels.map((m) => ({
@ -765,8 +785,8 @@ export async function applyAuthChoiceApiProviders(
normalizedModelId = String(modelId).trim(); normalizedModelId = String(modelId).trim();
} }
// If context window wasn't auto-detected, prompt for it // If context window wasn't auto-detected, prompt for it (skip in non-interactive mode)
if (!contextWindow) { if (!contextWindow && !params.opts?.nonInteractive) {
const contextInput = await params.prompter.text({ const contextInput = await params.prompter.text({
message: "Enter context window size (tokens)", message: "Enter context window size (tokens)",
initialValue: "128000", initialValue: "128000",

View File

@ -24,6 +24,12 @@ export type ApplyAuthChoiceParams = {
opts?: { opts?: {
tokenProvider?: string; tokenProvider?: string;
token?: string; token?: string;
// LiteLLM-specific options
litellmApiKey?: string;
litellmBaseUrl?: string;
litellmModel?: string;
// Non-interactive mode flag
nonInteractive?: boolean;
}; };
}; };

View File

@ -417,7 +417,7 @@ export function applyVeniceConfig(cfg: MoltbotConfig): MoltbotConfig {
* are user-configurable. * are user-configurable.
*/ */
export function applyLitellmProviderConfig( export function applyLitellmProviderConfig(
cfg: ClawdbotConfig, cfg: MoltbotConfig,
params: { params: {
baseUrl: string; baseUrl: string;
modelId: string; modelId: string;
@ -425,7 +425,7 @@ export function applyLitellmProviderConfig(
contextWindow?: number; contextWindow?: number;
maxTokens?: number; maxTokens?: number;
}, },
): ClawdbotConfig { ): MoltbotConfig {
const modelRef = `litellm/${params.modelId}`; const modelRef = `litellm/${params.modelId}`;
const models = { ...cfg.agents?.defaults?.models }; const models = { ...cfg.agents?.defaults?.models };
models[modelRef] = { models[modelRef] = {
@ -485,7 +485,7 @@ export function applyLitellmProviderConfig(
* Use this when LiteLLM is the primary provider choice during onboarding. * Use this when LiteLLM is the primary provider choice during onboarding.
*/ */
export function applyLitellmConfig( export function applyLitellmConfig(
cfg: ClawdbotConfig, cfg: MoltbotConfig,
params: { params: {
baseUrl: string; baseUrl: string;
modelId: string; modelId: string;
@ -493,7 +493,7 @@ export function applyLitellmConfig(
contextWindow?: number; contextWindow?: number;
maxTokens?: number; maxTokens?: number;
}, },
): ClawdbotConfig { ): MoltbotConfig {
const next = applyLitellmProviderConfig(cfg, params); const next = applyLitellmProviderConfig(cfg, params);
const modelRef = `litellm/${params.modelId}`; const modelRef = `litellm/${params.modelId}`;
const existingModel = next.agents?.defaults?.model; const existingModel = next.agents?.defaults?.model;