diff --git a/src/commands/models/fallbacks.ts b/src/commands/models/fallbacks.ts index fcb729b05b0..a3e57390c60 100644 --- a/src/commands/models/fallbacks.ts +++ b/src/commands/models/fallbacks.ts @@ -5,6 +5,8 @@ import { logConfigUpdated } from "../../config/logging.js"; import { DEFAULT_PROVIDER, ensureFlagCompatibility, + mergePrimaryFallbackConfig, + type PrimaryFallbackConfig, modelKey, resolveModelTarget, resolveModelKeysFromEntries, @@ -55,20 +57,16 @@ export async function modelsFallbacksAddCommand(modelRaw: string, runtime: Runti return cfg; } - const existingModel = cfg.agents?.defaults?.model as - | { primary?: string; fallbacks?: string[] } - | undefined; - return { ...cfg, agents: { ...cfg.agents, defaults: { ...cfg.agents?.defaults, - model: { - ...(existingModel?.primary ? { primary: existingModel.primary } : undefined), - fallbacks: [...existing, targetKey], - }, + model: mergePrimaryFallbackConfig( + cfg.agents?.defaults?.model as unknown as PrimaryFallbackConfig | undefined, + { fallbacks: [...existing, targetKey] }, + ), models: nextModels, }, }, @@ -104,20 +102,16 @@ export async function modelsFallbacksRemoveCommand(modelRaw: string, runtime: Ru throw new Error(`Fallback not found: ${targetKey}`); } - const existingModel = cfg.agents?.defaults?.model as - | { primary?: string; fallbacks?: string[] } - | undefined; - return { ...cfg, agents: { ...cfg.agents, defaults: { ...cfg.agents?.defaults, - model: { - ...(existingModel?.primary ? { primary: existingModel.primary } : undefined), - fallbacks: filtered, - }, + model: mergePrimaryFallbackConfig( + cfg.agents?.defaults?.model as unknown as PrimaryFallbackConfig | undefined, + { fallbacks: filtered }, + ), }, }, }; @@ -129,19 +123,16 @@ export async function modelsFallbacksRemoveCommand(modelRaw: string, runtime: Ru export async function modelsFallbacksClearCommand(runtime: RuntimeEnv) { await updateConfig((cfg) => { - const existingModel = cfg.agents?.defaults?.model as - | { primary?: string; fallbacks?: string[] } - | undefined; return { ...cfg, agents: { ...cfg.agents, defaults: { ...cfg.agents?.defaults, - model: { - ...(existingModel?.primary ? { primary: existingModel.primary } : undefined), - fallbacks: [], - }, + model: mergePrimaryFallbackConfig( + cfg.agents?.defaults?.model as unknown as PrimaryFallbackConfig | undefined, + { fallbacks: [] }, + ), }, }, }; diff --git a/src/commands/models/image-fallbacks.ts b/src/commands/models/image-fallbacks.ts index 53e1fd2306b..43d1f51c60a 100644 --- a/src/commands/models/image-fallbacks.ts +++ b/src/commands/models/image-fallbacks.ts @@ -5,6 +5,8 @@ import { logConfigUpdated } from "../../config/logging.js"; import { DEFAULT_PROVIDER, ensureFlagCompatibility, + mergePrimaryFallbackConfig, + type PrimaryFallbackConfig, modelKey, resolveModelTarget, resolveModelKeysFromEntries, @@ -55,20 +57,16 @@ export async function modelsImageFallbacksAddCommand(modelRaw: string, runtime: return cfg; } - const existingModel = cfg.agents?.defaults?.imageModel as - | { primary?: string; fallbacks?: string[] } - | undefined; - return { ...cfg, agents: { ...cfg.agents, defaults: { ...cfg.agents?.defaults, - imageModel: { - ...(existingModel?.primary ? { primary: existingModel.primary } : undefined), - fallbacks: [...existing, targetKey], - }, + imageModel: mergePrimaryFallbackConfig( + cfg.agents?.defaults?.imageModel as unknown as PrimaryFallbackConfig | undefined, + { fallbacks: [...existing, targetKey] }, + ), models: nextModels, }, }, @@ -106,20 +104,16 @@ export async function modelsImageFallbacksRemoveCommand(modelRaw: string, runtim throw new Error(`Image fallback not found: ${targetKey}`); } - const existingModel = cfg.agents?.defaults?.imageModel as - | { primary?: string; fallbacks?: string[] } - | undefined; - return { ...cfg, agents: { ...cfg.agents, defaults: { ...cfg.agents?.defaults, - imageModel: { - ...(existingModel?.primary ? { primary: existingModel.primary } : undefined), - fallbacks: filtered, - }, + imageModel: mergePrimaryFallbackConfig( + cfg.agents?.defaults?.imageModel as unknown as PrimaryFallbackConfig | undefined, + { fallbacks: filtered }, + ), }, }, }; @@ -133,19 +127,16 @@ export async function modelsImageFallbacksRemoveCommand(modelRaw: string, runtim export async function modelsImageFallbacksClearCommand(runtime: RuntimeEnv) { await updateConfig((cfg) => { - const existingModel = cfg.agents?.defaults?.imageModel as - | { primary?: string; fallbacks?: string[] } - | undefined; return { ...cfg, agents: { ...cfg.agents, defaults: { ...cfg.agents?.defaults, - imageModel: { - ...(existingModel?.primary ? { primary: existingModel.primary } : undefined), - fallbacks: [], - }, + imageModel: mergePrimaryFallbackConfig( + cfg.agents?.defaults?.imageModel as unknown as PrimaryFallbackConfig | undefined, + { fallbacks: [] }, + ), }, }, }; diff --git a/src/commands/models/set-image.ts b/src/commands/models/set-image.ts index 82531414ef2..0b15ff5e670 100644 --- a/src/commands/models/set-image.ts +++ b/src/commands/models/set-image.ts @@ -1,6 +1,11 @@ import type { RuntimeEnv } from "../../runtime.js"; import { logConfigUpdated } from "../../config/logging.js"; -import { resolveModelTarget, updateConfig } from "./shared.js"; +import { + mergePrimaryFallbackConfig, + type PrimaryFallbackConfig, + resolveModelTarget, + updateConfig, +} from "./shared.js"; export async function modelsSetImageCommand(modelRaw: string, runtime: RuntimeEnv) { const updated = await updateConfig((cfg) => { @@ -10,19 +15,16 @@ export async function modelsSetImageCommand(modelRaw: string, runtime: RuntimeEn if (!nextModels[key]) { nextModels[key] = {}; } - const existingModel = cfg.agents?.defaults?.imageModel as - | { primary?: string; fallbacks?: string[] } - | undefined; return { ...cfg, agents: { ...cfg.agents, defaults: { ...cfg.agents?.defaults, - imageModel: { - ...(existingModel?.fallbacks ? { fallbacks: existingModel.fallbacks } : undefined), - primary: key, - }, + imageModel: mergePrimaryFallbackConfig( + cfg.agents?.defaults?.imageModel as unknown as PrimaryFallbackConfig | undefined, + { primary: key }, + ), models: nextModels, }, }, diff --git a/src/commands/models/set.ts b/src/commands/models/set.ts index 83db6723fbd..a6291f72696 100644 --- a/src/commands/models/set.ts +++ b/src/commands/models/set.ts @@ -1,6 +1,11 @@ import type { RuntimeEnv } from "../../runtime.js"; import { logConfigUpdated } from "../../config/logging.js"; -import { resolveModelTarget, updateConfig } from "./shared.js"; +import { + mergePrimaryFallbackConfig, + type PrimaryFallbackConfig, + resolveModelTarget, + updateConfig, +} from "./shared.js"; export async function modelsSetCommand(modelRaw: string, runtime: RuntimeEnv) { const updated = await updateConfig((cfg) => { @@ -10,19 +15,16 @@ export async function modelsSetCommand(modelRaw: string, runtime: RuntimeEnv) { if (!nextModels[key]) { nextModels[key] = {}; } - const existingModel = cfg.agents?.defaults?.model as - | { primary?: string; fallbacks?: string[] } - | undefined; return { ...cfg, agents: { ...cfg.agents, defaults: { ...cfg.agents?.defaults, - model: { - ...(existingModel?.fallbacks ? { fallbacks: existingModel.fallbacks } : undefined), - primary: key, - }, + model: mergePrimaryFallbackConfig( + cfg.agents?.defaults?.model as unknown as PrimaryFallbackConfig | undefined, + { primary: key }, + ), models: nextModels, }, }, diff --git a/src/commands/models/shared.ts b/src/commands/models/shared.ts index 002e839e23e..9f65eebf8f1 100644 --- a/src/commands/models/shared.ts +++ b/src/commands/models/shared.ts @@ -153,6 +153,22 @@ export function resolveKnownAgentId(params: { return agentId; } +export type PrimaryFallbackConfig = { primary?: string; fallbacks?: string[] }; + +export function mergePrimaryFallbackConfig( + existing: PrimaryFallbackConfig | undefined, + patch: { primary?: string; fallbacks?: string[] }, +): PrimaryFallbackConfig { + const next: PrimaryFallbackConfig = { ...existing }; + if (patch.primary !== undefined) { + next.primary = patch.primary; + } + if (patch.fallbacks !== undefined) { + next.fallbacks = patch.fallbacks; + } + return next; +} + export { modelKey }; export { DEFAULT_MODEL, DEFAULT_PROVIDER };