import { buildSyntheticModelDefinition, SYNTHETIC_BASE_URL, SYNTHETIC_DEFAULT_MODEL_REF, SYNTHETIC_MODEL_CATALOG, } from "../agents/synthetic-models.js"; import type { ClawdbotConfig } from "../config/config.js"; import { OPENROUTER_DEFAULT_MODEL_REF, VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF, ZAI_DEFAULT_MODEL_REF, } from "./onboard-auth.credentials.js"; import { buildMoonshotModelDefinition, MOONSHOT_BASE_URL, MOONSHOT_DEFAULT_MODEL_ID, MOONSHOT_DEFAULT_MODEL_REF, } from "./onboard-auth.models.js"; export function applyZaiConfig(cfg: ClawdbotConfig): ClawdbotConfig { const models = { ...cfg.agents?.defaults?.models }; models[ZAI_DEFAULT_MODEL_REF] = { ...models[ZAI_DEFAULT_MODEL_REF], alias: models[ZAI_DEFAULT_MODEL_REF]?.alias ?? "GLM", }; const existingModel = cfg.agents?.defaults?.model; return { ...cfg, agents: { ...cfg.agents, defaults: { ...cfg.agents?.defaults, models, model: { ...(existingModel && "fallbacks" in (existingModel as Record) ? { fallbacks: (existingModel as { fallbacks?: string[] }).fallbacks, } : undefined), primary: ZAI_DEFAULT_MODEL_REF, }, }, }, }; } export function applyOpenrouterProviderConfig(cfg: ClawdbotConfig): ClawdbotConfig { const models = { ...cfg.agents?.defaults?.models }; models[OPENROUTER_DEFAULT_MODEL_REF] = { ...models[OPENROUTER_DEFAULT_MODEL_REF], alias: models[OPENROUTER_DEFAULT_MODEL_REF]?.alias ?? "OpenRouter", }; return { ...cfg, agents: { ...cfg.agents, defaults: { ...cfg.agents?.defaults, models, }, }, }; } export function applyVercelAiGatewayProviderConfig(cfg: ClawdbotConfig): ClawdbotConfig { const models = { ...cfg.agents?.defaults?.models }; models[VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF] = { ...models[VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF], alias: models[VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF]?.alias ?? "Vercel AI Gateway", }; return { ...cfg, agents: { ...cfg.agents, defaults: { ...cfg.agents?.defaults, models, }, }, }; } export function applyVercelAiGatewayConfig(cfg: ClawdbotConfig): ClawdbotConfig { const next = applyVercelAiGatewayProviderConfig(cfg); const existingModel = next.agents?.defaults?.model; return { ...next, agents: { ...next.agents, defaults: { ...next.agents?.defaults, model: { ...(existingModel && "fallbacks" in (existingModel as Record) ? { fallbacks: (existingModel as { fallbacks?: string[] }).fallbacks, } : undefined), primary: VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF, }, }, }, }; } export function applyOpenrouterConfig(cfg: ClawdbotConfig): ClawdbotConfig { const next = applyOpenrouterProviderConfig(cfg); const existingModel = next.agents?.defaults?.model; return { ...next, agents: { ...next.agents, defaults: { ...next.agents?.defaults, model: { ...(existingModel && "fallbacks" in (existingModel as Record) ? { fallbacks: (existingModel as { fallbacks?: string[] }).fallbacks, } : undefined), primary: OPENROUTER_DEFAULT_MODEL_REF, }, }, }, }; } export function applyMoonshotProviderConfig(cfg: ClawdbotConfig): ClawdbotConfig { const models = { ...cfg.agents?.defaults?.models }; models[MOONSHOT_DEFAULT_MODEL_REF] = { ...models[MOONSHOT_DEFAULT_MODEL_REF], alias: models[MOONSHOT_DEFAULT_MODEL_REF]?.alias ?? "Kimi K2", }; 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: MOONSHOT_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, }, }; } export function applyMoonshotConfig(cfg: ClawdbotConfig): ClawdbotConfig { const next = applyMoonshotProviderConfig(cfg); const existingModel = next.agents?.defaults?.model; return { ...next, agents: { ...next.agents, defaults: { ...next.agents?.defaults, model: { ...(existingModel && "fallbacks" in (existingModel as Record) ? { fallbacks: (existingModel as { fallbacks?: string[] }).fallbacks, } : undefined), primary: MOONSHOT_DEFAULT_MODEL_REF, }, }, }, }; } export function applySyntheticProviderConfig(cfg: ClawdbotConfig): ClawdbotConfig { const models = { ...cfg.agents?.defaults?.models }; models[SYNTHETIC_DEFAULT_MODEL_REF] = { ...models[SYNTHETIC_DEFAULT_MODEL_REF], alias: models[SYNTHETIC_DEFAULT_MODEL_REF]?.alias ?? "MiniMax M2.1", }; const providers = { ...cfg.models?.providers }; const existingProvider = providers.synthetic; const existingModels = Array.isArray(existingProvider?.models) ? existingProvider.models : []; const syntheticModels = SYNTHETIC_MODEL_CATALOG.map(buildSyntheticModelDefinition); const mergedModels = [ ...existingModels, ...syntheticModels.filter( (model) => !existingModels.some((existing) => existing.id === model.id), ), ]; const { apiKey: existingApiKey, ...existingProviderRest } = (existingProvider ?? {}) as Record< string, unknown > as { apiKey?: string }; const resolvedApiKey = typeof existingApiKey === "string" ? existingApiKey : undefined; const normalizedApiKey = resolvedApiKey?.trim(); providers.synthetic = { ...existingProviderRest, baseUrl: SYNTHETIC_BASE_URL, api: "anthropic-messages", ...(normalizedApiKey ? { apiKey: normalizedApiKey } : {}), models: mergedModels.length > 0 ? mergedModels : syntheticModels, }; return { ...cfg, agents: { ...cfg.agents, defaults: { ...cfg.agents?.defaults, models, }, }, models: { mode: cfg.models?.mode ?? "merge", providers, }, }; } export function applySyntheticConfig(cfg: ClawdbotConfig): ClawdbotConfig { const next = applySyntheticProviderConfig(cfg); const existingModel = next.agents?.defaults?.model; return { ...next, agents: { ...next.agents, defaults: { ...next.agents?.defaults, model: { ...(existingModel && "fallbacks" in (existingModel as Record) ? { fallbacks: (existingModel as { fallbacks?: string[] }).fallbacks, } : undefined), primary: SYNTHETIC_DEFAULT_MODEL_REF, }, }, }, }; } export function applyAuthProfileConfig( cfg: ClawdbotConfig, params: { profileId: string; provider: string; mode: "api_key" | "oauth" | "token"; email?: string; preferProfileFirst?: boolean; }, ): ClawdbotConfig { const profiles = { ...cfg.auth?.profiles, [params.profileId]: { provider: params.provider, mode: params.mode, ...(params.email ? { email: params.email } : {}), }, }; // Only maintain `auth.order` when the user explicitly configured it. // Default behavior: no explicit order -> resolveAuthProfileOrder can round-robin by lastUsed. const existingProviderOrder = cfg.auth?.order?.[params.provider]; const preferProfileFirst = params.preferProfileFirst ?? true; const reorderedProviderOrder = existingProviderOrder && preferProfileFirst ? [ params.profileId, ...existingProviderOrder.filter((profileId) => profileId !== params.profileId), ] : existingProviderOrder; const order = existingProviderOrder !== undefined ? { ...cfg.auth?.order, [params.provider]: reorderedProviderOrder?.includes(params.profileId) ? reorderedProviderOrder : [...(reorderedProviderOrder ?? []), params.profileId], } : cfg.auth?.order; return { ...cfg, auth: { ...cfg.auth, profiles, ...(order ? { order } : {}), }, }; }