From 2b52ded88295457ddf19d6dc6698f26eb4dfb328 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 15 Feb 2026 05:21:11 +0000 Subject: [PATCH] refactor(commands): share provider config merge helper --- src/commands/onboard-auth.config-core.ts | 81 ++++---------------- src/commands/onboard-auth.config-gateways.ts | 46 ++++------- src/commands/onboard-auth.config-litellm.ts | 43 +++-------- src/commands/onboard-auth.config-shared.ts | 59 ++++++++++++++ 4 files changed, 100 insertions(+), 129 deletions(-) create mode 100644 src/commands/onboard-auth.config-shared.ts diff --git a/src/commands/onboard-auth.config-core.ts b/src/commands/onboard-auth.config-core.ts index 7a55db668..1b2252ffc 100644 --- a/src/commands/onboard-auth.config-core.ts +++ b/src/commands/onboard-auth.config-core.ts @@ -48,6 +48,7 @@ export { LITELLM_BASE_URL, LITELLM_DEFAULT_MODEL_ID, } from "./onboard-auth.config-litellm.js"; +import { applyProviderConfigWithDefaultModel } from "./onboard-auth.config-shared.js"; import { buildZaiModelDefinition, buildMoonshotModelDefinition, @@ -221,40 +222,16 @@ function applyMoonshotProviderConfigWithBaseUrl( alias: models[MOONSHOT_DEFAULT_MODEL_REF]?.alias ?? "Kimi", }; - const providers = { ...cfg.models?.providers }; - const existingProvider = providers.moonshot; - const existingModels = Array.isArray(existingProvider?.models) ? existingProvider.models : []; const defaultModel = buildMoonshotModelDefinition(); - const hasDefaultModel = existingModels.some((model) => model.id === MOONSHOT_DEFAULT_MODEL_ID); - const mergedModels = hasDefaultModel ? existingModels : [...existingModels, defaultModel]; - const { apiKey: existingApiKey, ...existingProviderRest } = (existingProvider ?? {}) as Record< - string, - unknown - > as { apiKey?: string }; - const resolvedApiKey = typeof existingApiKey === "string" ? existingApiKey : undefined; - const normalizedApiKey = resolvedApiKey?.trim(); - providers.moonshot = { - ...existingProviderRest, - baseUrl, - api: "openai-completions", - ...(normalizedApiKey ? { apiKey: normalizedApiKey } : {}), - models: mergedModels.length > 0 ? mergedModels : [defaultModel], - }; - return { - ...cfg, - agents: { - ...cfg.agents, - defaults: { - ...cfg.agents?.defaults, - models, - }, - }, - models: { - mode: cfg.models?.mode ?? "merge", - providers, - }, - }; + return applyProviderConfigWithDefaultModel(cfg, { + agentModels: models, + providerId: "moonshot", + api: "openai-completions", + baseUrl, + defaultModel, + defaultModelId: MOONSHOT_DEFAULT_MODEL_ID, + }); } export function applyMoonshotConfig(cfg: OpenClawConfig): OpenClawConfig { @@ -714,40 +691,16 @@ export function applyXaiProviderConfig(cfg: OpenClawConfig): OpenClawConfig { alias: models[XAI_DEFAULT_MODEL_REF]?.alias ?? "Grok", }; - const providers = { ...cfg.models?.providers }; - const existingProvider = providers.xai; - const existingModels = Array.isArray(existingProvider?.models) ? existingProvider.models : []; const defaultModel = buildXaiModelDefinition(); - const hasDefaultModel = existingModels.some((model) => model.id === XAI_DEFAULT_MODEL_ID); - const mergedModels = hasDefaultModel ? existingModels : [...existingModels, defaultModel]; - const { apiKey: existingApiKey, ...existingProviderRest } = (existingProvider ?? {}) as Record< - string, - unknown - > as { apiKey?: string }; - const resolvedApiKey = typeof existingApiKey === "string" ? existingApiKey : undefined; - const normalizedApiKey = resolvedApiKey?.trim(); - providers.xai = { - ...existingProviderRest, - baseUrl: XAI_BASE_URL, - api: "openai-completions", - ...(normalizedApiKey ? { apiKey: normalizedApiKey } : {}), - models: mergedModels.length > 0 ? mergedModels : [defaultModel], - }; - return { - ...cfg, - agents: { - ...cfg.agents, - defaults: { - ...cfg.agents?.defaults, - models, - }, - }, - models: { - mode: cfg.models?.mode ?? "merge", - providers, - }, - }; + return applyProviderConfigWithDefaultModel(cfg, { + agentModels: models, + providerId: "xai", + api: "openai-completions", + baseUrl: XAI_BASE_URL, + defaultModel, + defaultModelId: XAI_DEFAULT_MODEL_ID, + }); } export function applyXaiConfig(cfg: OpenClawConfig): OpenClawConfig { diff --git a/src/commands/onboard-auth.config-gateways.ts b/src/commands/onboard-auth.config-gateways.ts index b380dfa1f..1e4ffc62c 100644 --- a/src/commands/onboard-auth.config-gateways.ts +++ b/src/commands/onboard-auth.config-gateways.ts @@ -3,6 +3,7 @@ import { buildCloudflareAiGatewayModelDefinition, resolveCloudflareAiGatewayBaseUrl, } from "../agents/cloudflare-ai-gateway.js"; +import { applyProviderConfigWithDefaultModel } from "./onboard-auth.config-shared.js"; import { CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_REF, VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF, @@ -37,19 +38,19 @@ export function applyCloudflareAiGatewayProviderConfig( alias: models[CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_REF]?.alias ?? "Cloudflare AI Gateway", }; - const providers = { ...cfg.models?.providers }; - const existingProvider = providers["cloudflare-ai-gateway"]; - const existingModels = Array.isArray(existingProvider?.models) ? existingProvider.models : []; const defaultModel = buildCloudflareAiGatewayModelDefinition(); - const hasDefaultModel = existingModels.some((model) => model.id === defaultModel.id); - const mergedModels = hasDefaultModel ? existingModels : [...existingModels, defaultModel]; + const existingProvider = cfg.models?.providers?.["cloudflare-ai-gateway"] as + | { baseUrl?: unknown } + | undefined; const baseUrl = params?.accountId && params?.gatewayId ? resolveCloudflareAiGatewayBaseUrl({ accountId: params.accountId, gatewayId: params.gatewayId, }) - : existingProvider?.baseUrl; + : typeof existingProvider?.baseUrl === "string" + ? existingProvider.baseUrl + : undefined; if (!baseUrl) { return { @@ -64,34 +65,13 @@ export function applyCloudflareAiGatewayProviderConfig( }; } - const { apiKey: existingApiKey, ...existingProviderRest } = (existingProvider ?? {}) as Record< - string, - unknown - > as { apiKey?: string }; - const resolvedApiKey = typeof existingApiKey === "string" ? existingApiKey : undefined; - const normalizedApiKey = resolvedApiKey?.trim(); - providers["cloudflare-ai-gateway"] = { - ...existingProviderRest, - baseUrl, + return applyProviderConfigWithDefaultModel(cfg, { + agentModels: models, + providerId: "cloudflare-ai-gateway", api: "anthropic-messages", - ...(normalizedApiKey ? { apiKey: normalizedApiKey } : {}), - models: mergedModels.length > 0 ? mergedModels : [defaultModel], - }; - - return { - ...cfg, - agents: { - ...cfg.agents, - defaults: { - ...cfg.agents?.defaults, - models, - }, - }, - models: { - mode: cfg.models?.mode ?? "merge", - providers, - }, - }; + baseUrl, + defaultModel, + }); } export function applyVercelAiGatewayConfig(cfg: OpenClawConfig): OpenClawConfig { diff --git a/src/commands/onboard-auth.config-litellm.ts b/src/commands/onboard-auth.config-litellm.ts index 622e49fe6..29041f1d5 100644 --- a/src/commands/onboard-auth.config-litellm.ts +++ b/src/commands/onboard-auth.config-litellm.ts @@ -1,4 +1,5 @@ import type { OpenClawConfig } from "../config/config.js"; +import { applyProviderConfigWithDefaultModel } from "./onboard-auth.config-shared.js"; import { LITELLM_DEFAULT_MODEL_REF } from "./onboard-auth.credentials.js"; export const LITELLM_BASE_URL = "http://localhost:4000"; @@ -39,42 +40,20 @@ export function applyLitellmProviderConfig(cfg: OpenClawConfig): OpenClawConfig alias: models[LITELLM_DEFAULT_MODEL_REF]?.alias ?? "LiteLLM", }; - const providers = { ...cfg.models?.providers }; - const existingProvider = providers.litellm; - const existingModels = Array.isArray(existingProvider?.models) ? existingProvider.models : []; const defaultModel = buildLitellmModelDefinition(); - const hasDefaultModel = existingModels.some((model) => model.id === LITELLM_DEFAULT_MODEL_ID); - const mergedModels = hasDefaultModel ? existingModels : [...existingModels, defaultModel]; - const { apiKey: existingApiKey, ...existingProviderRest } = (existingProvider ?? {}) as Record< - string, - unknown - > as { apiKey?: string }; + + const existingProvider = cfg.models?.providers?.litellm as { baseUrl?: unknown } | undefined; const resolvedBaseUrl = typeof existingProvider?.baseUrl === "string" ? existingProvider.baseUrl.trim() : ""; - const resolvedApiKey = typeof existingApiKey === "string" ? existingApiKey : undefined; - const normalizedApiKey = resolvedApiKey?.trim(); - providers.litellm = { - ...existingProviderRest, - baseUrl: resolvedBaseUrl || LITELLM_BASE_URL, - api: "openai-completions", - ...(normalizedApiKey ? { apiKey: normalizedApiKey } : {}), - models: mergedModels.length > 0 ? mergedModels : [defaultModel], - }; - return { - ...cfg, - agents: { - ...cfg.agents, - defaults: { - ...cfg.agents?.defaults, - models, - }, - }, - models: { - mode: cfg.models?.mode ?? "merge", - providers, - }, - }; + return applyProviderConfigWithDefaultModel(cfg, { + agentModels: models, + providerId: "litellm", + api: "openai-completions", + baseUrl: resolvedBaseUrl || LITELLM_BASE_URL, + defaultModel, + defaultModelId: LITELLM_DEFAULT_MODEL_ID, + }); } export function applyLitellmConfig(cfg: OpenClawConfig): OpenClawConfig { diff --git a/src/commands/onboard-auth.config-shared.ts b/src/commands/onboard-auth.config-shared.ts new file mode 100644 index 000000000..3b7995f00 --- /dev/null +++ b/src/commands/onboard-auth.config-shared.ts @@ -0,0 +1,59 @@ +import type { OpenClawConfig } from "../config/config.js"; +import type { AgentModelEntryConfig } from "../config/types.agent-defaults.js"; +import type { + ModelApi, + ModelDefinitionConfig, + ModelProviderConfig, +} from "../config/types.models.js"; + +export function applyProviderConfigWithDefaultModel( + cfg: OpenClawConfig, + params: { + agentModels: Record; + providerId: string; + api: ModelApi; + baseUrl: string; + defaultModel: ModelDefinitionConfig; + defaultModelId?: string; + }, +): OpenClawConfig { + const providers = { ...cfg.models?.providers } as Record; + const existingProvider = providers[params.providerId] as ModelProviderConfig | undefined; + + const existingModels: ModelDefinitionConfig[] = Array.isArray(existingProvider?.models) + ? existingProvider.models + : []; + + const defaultModelId = params.defaultModelId ?? params.defaultModel.id; + const hasDefaultModel = existingModels.some((model) => model.id === defaultModelId); + const mergedModels = hasDefaultModel ? existingModels : [...existingModels, params.defaultModel]; + + const { apiKey: existingApiKey, ...existingProviderRest } = (existingProvider ?? {}) as { + apiKey?: string; + }; + + const normalizedApiKey = typeof existingApiKey === "string" ? existingApiKey.trim() : undefined; + + providers[params.providerId] = { + ...existingProviderRest, + baseUrl: params.baseUrl, + api: params.api, + ...(normalizedApiKey ? { apiKey: normalizedApiKey } : {}), + models: mergedModels.length > 0 ? mergedModels : [params.defaultModel], + }; + + return { + ...cfg, + agents: { + ...cfg.agents, + defaults: { + ...cfg.agents?.defaults, + models: params.agentModels, + }, + }, + models: { + mode: cfg.models?.mode ?? "merge", + providers, + }, + }; +}