fix(litellm): handle AUTH_CHOICE_CANCELLED to retry auth selection

- Add retry loops in configure.gateway-auth and agents.commands.add
- Catch AUTH_CHOICE_CANCELLED error and re-prompt for auth method
- Users can now go back to auth method selection when LiteLLM setup fails
- Import AuthChoice type for proper typing

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Charles-Henri ROBICHE 2026-01-29 10:59:30 +01:00
parent d531f7d9a4
commit ce8fd694ae
No known key found for this signature in database
2 changed files with 75 additions and 44 deletions

View File

@ -254,12 +254,16 @@ export async function agentsAddCommand(
const authStore = ensureAuthProfileStore(agentDir, { const authStore = ensureAuthProfileStore(agentDir, {
allowKeychainPrompt: false, allowKeychainPrompt: false,
}); });
// Loop to allow retrying auth choice if user cancels during configuration
while (true) {
const authChoice = await promptAuthChoiceGrouped({ const authChoice = await promptAuthChoiceGrouped({
prompter, prompter,
store: authStore, store: authStore,
includeSkip: true, includeSkip: true,
}); });
try {
const authResult = await applyAuthChoice({ const authResult = await applyAuthChoice({
authChoice, authChoice,
config: nextConfig, config: nextConfig,
@ -276,6 +280,16 @@ export async function agentsAddCommand(
model: authResult.agentModelOverride, model: authResult.agentModelOverride,
}); });
} }
break; // Success - exit the loop
} catch (error) {
// If user cancelled to go back to auth selection, loop again
if (error instanceof Error && error.message === "AUTH_CHOICE_CANCELLED") {
continue;
}
// Re-throw other errors
throw error;
}
}
} }
await warnIfModelConfigLooksOff(nextConfig, prompter, { await warnIfModelConfigLooksOff(nextConfig, prompter, {

View File

@ -4,6 +4,7 @@ import type { RuntimeEnv } from "../runtime.js";
import type { WizardPrompter } from "../wizard/prompts.js"; import type { WizardPrompter } from "../wizard/prompts.js";
import { applyAuthChoice, resolvePreferredProviderForAuthChoice } from "./auth-choice.js"; import { applyAuthChoice, resolvePreferredProviderForAuthChoice } from "./auth-choice.js";
import { promptAuthChoiceGrouped } from "./auth-choice-prompt.js"; import { promptAuthChoiceGrouped } from "./auth-choice-prompt.js";
import type { AuthChoice } from "./onboard-types.js";
import { import {
applyModelAllowlist, applyModelAllowlist,
applyModelFallbacksFromSelection, applyModelFallbacksFromSelection,
@ -41,7 +42,12 @@ export async function promptAuthConfig(
runtime: RuntimeEnv, runtime: RuntimeEnv,
prompter: WizardPrompter, prompter: WizardPrompter,
): Promise<MoltbotConfig> { ): Promise<MoltbotConfig> {
const authChoice = await promptAuthChoiceGrouped({ let next = cfg;
let authChoice: AuthChoice;
// Loop to allow retrying auth choice if user cancels during configuration
while (true) {
authChoice = await promptAuthChoiceGrouped({
prompter, prompter,
store: ensureAuthProfileStore(undefined, { store: ensureAuthProfileStore(undefined, {
allowKeychainPrompt: false, allowKeychainPrompt: false,
@ -49,8 +55,8 @@ export async function promptAuthConfig(
includeSkip: true, includeSkip: true,
}); });
let next = cfg;
if (authChoice !== "skip") { if (authChoice !== "skip") {
try {
const applied = await applyAuthChoice({ const applied = await applyAuthChoice({
authChoice, authChoice,
config: next, config: next,
@ -59,6 +65,15 @@ export async function promptAuthConfig(
setDefaultModel: true, setDefaultModel: true,
}); });
next = applied.config; next = applied.config;
break; // Success - exit the loop
} catch (error) {
// If user cancelled to go back to auth selection, loop again
if (error instanceof Error && error.message === "AUTH_CHOICE_CANCELLED") {
continue;
}
// Re-throw other errors
throw error;
}
} else { } else {
const modelSelection = await promptDefaultModel({ const modelSelection = await promptDefaultModel({
config: next, config: next,
@ -70,6 +85,8 @@ export async function promptAuthConfig(
if (modelSelection.model) { if (modelSelection.model) {
next = applyPrimaryModel(next, modelSelection.model); next = applyPrimaryModel(next, modelSelection.model);
} }
break; // Skip selected - exit the loop
}
} }
const anthropicOAuth = const anthropicOAuth =