refactor(models): share primary/fallback merge

This commit is contained in:
Peter Steinberger
2026-02-15 17:13:09 +00:00
parent 3ce0e80f57
commit cbf6ee3a64
5 changed files with 64 additions and 62 deletions

View File

@@ -5,6 +5,8 @@ import { logConfigUpdated } from "../../config/logging.js";
import { import {
DEFAULT_PROVIDER, DEFAULT_PROVIDER,
ensureFlagCompatibility, ensureFlagCompatibility,
mergePrimaryFallbackConfig,
type PrimaryFallbackConfig,
modelKey, modelKey,
resolveModelTarget, resolveModelTarget,
resolveModelKeysFromEntries, resolveModelKeysFromEntries,
@@ -55,20 +57,16 @@ export async function modelsFallbacksAddCommand(modelRaw: string, runtime: Runti
return cfg; return cfg;
} }
const existingModel = cfg.agents?.defaults?.model as
| { primary?: string; fallbacks?: string[] }
| undefined;
return { return {
...cfg, ...cfg,
agents: { agents: {
...cfg.agents, ...cfg.agents,
defaults: { defaults: {
...cfg.agents?.defaults, ...cfg.agents?.defaults,
model: { model: mergePrimaryFallbackConfig(
...(existingModel?.primary ? { primary: existingModel.primary } : undefined), cfg.agents?.defaults?.model as unknown as PrimaryFallbackConfig | undefined,
fallbacks: [...existing, targetKey], { fallbacks: [...existing, targetKey] },
}, ),
models: nextModels, models: nextModels,
}, },
}, },
@@ -104,20 +102,16 @@ export async function modelsFallbacksRemoveCommand(modelRaw: string, runtime: Ru
throw new Error(`Fallback not found: ${targetKey}`); throw new Error(`Fallback not found: ${targetKey}`);
} }
const existingModel = cfg.agents?.defaults?.model as
| { primary?: string; fallbacks?: string[] }
| undefined;
return { return {
...cfg, ...cfg,
agents: { agents: {
...cfg.agents, ...cfg.agents,
defaults: { defaults: {
...cfg.agents?.defaults, ...cfg.agents?.defaults,
model: { model: mergePrimaryFallbackConfig(
...(existingModel?.primary ? { primary: existingModel.primary } : undefined), cfg.agents?.defaults?.model as unknown as PrimaryFallbackConfig | undefined,
fallbacks: filtered, { fallbacks: filtered },
}, ),
}, },
}, },
}; };
@@ -129,19 +123,16 @@ export async function modelsFallbacksRemoveCommand(modelRaw: string, runtime: Ru
export async function modelsFallbacksClearCommand(runtime: RuntimeEnv) { export async function modelsFallbacksClearCommand(runtime: RuntimeEnv) {
await updateConfig((cfg) => { await updateConfig((cfg) => {
const existingModel = cfg.agents?.defaults?.model as
| { primary?: string; fallbacks?: string[] }
| undefined;
return { return {
...cfg, ...cfg,
agents: { agents: {
...cfg.agents, ...cfg.agents,
defaults: { defaults: {
...cfg.agents?.defaults, ...cfg.agents?.defaults,
model: { model: mergePrimaryFallbackConfig(
...(existingModel?.primary ? { primary: existingModel.primary } : undefined), cfg.agents?.defaults?.model as unknown as PrimaryFallbackConfig | undefined,
fallbacks: [], { fallbacks: [] },
}, ),
}, },
}, },
}; };

View File

@@ -5,6 +5,8 @@ import { logConfigUpdated } from "../../config/logging.js";
import { import {
DEFAULT_PROVIDER, DEFAULT_PROVIDER,
ensureFlagCompatibility, ensureFlagCompatibility,
mergePrimaryFallbackConfig,
type PrimaryFallbackConfig,
modelKey, modelKey,
resolveModelTarget, resolveModelTarget,
resolveModelKeysFromEntries, resolveModelKeysFromEntries,
@@ -55,20 +57,16 @@ export async function modelsImageFallbacksAddCommand(modelRaw: string, runtime:
return cfg; return cfg;
} }
const existingModel = cfg.agents?.defaults?.imageModel as
| { primary?: string; fallbacks?: string[] }
| undefined;
return { return {
...cfg, ...cfg,
agents: { agents: {
...cfg.agents, ...cfg.agents,
defaults: { defaults: {
...cfg.agents?.defaults, ...cfg.agents?.defaults,
imageModel: { imageModel: mergePrimaryFallbackConfig(
...(existingModel?.primary ? { primary: existingModel.primary } : undefined), cfg.agents?.defaults?.imageModel as unknown as PrimaryFallbackConfig | undefined,
fallbacks: [...existing, targetKey], { fallbacks: [...existing, targetKey] },
}, ),
models: nextModels, models: nextModels,
}, },
}, },
@@ -106,20 +104,16 @@ export async function modelsImageFallbacksRemoveCommand(modelRaw: string, runtim
throw new Error(`Image fallback not found: ${targetKey}`); throw new Error(`Image fallback not found: ${targetKey}`);
} }
const existingModel = cfg.agents?.defaults?.imageModel as
| { primary?: string; fallbacks?: string[] }
| undefined;
return { return {
...cfg, ...cfg,
agents: { agents: {
...cfg.agents, ...cfg.agents,
defaults: { defaults: {
...cfg.agents?.defaults, ...cfg.agents?.defaults,
imageModel: { imageModel: mergePrimaryFallbackConfig(
...(existingModel?.primary ? { primary: existingModel.primary } : undefined), cfg.agents?.defaults?.imageModel as unknown as PrimaryFallbackConfig | undefined,
fallbacks: filtered, { fallbacks: filtered },
}, ),
}, },
}, },
}; };
@@ -133,19 +127,16 @@ export async function modelsImageFallbacksRemoveCommand(modelRaw: string, runtim
export async function modelsImageFallbacksClearCommand(runtime: RuntimeEnv) { export async function modelsImageFallbacksClearCommand(runtime: RuntimeEnv) {
await updateConfig((cfg) => { await updateConfig((cfg) => {
const existingModel = cfg.agents?.defaults?.imageModel as
| { primary?: string; fallbacks?: string[] }
| undefined;
return { return {
...cfg, ...cfg,
agents: { agents: {
...cfg.agents, ...cfg.agents,
defaults: { defaults: {
...cfg.agents?.defaults, ...cfg.agents?.defaults,
imageModel: { imageModel: mergePrimaryFallbackConfig(
...(existingModel?.primary ? { primary: existingModel.primary } : undefined), cfg.agents?.defaults?.imageModel as unknown as PrimaryFallbackConfig | undefined,
fallbacks: [], { fallbacks: [] },
}, ),
}, },
}, },
}; };

View File

@@ -1,6 +1,11 @@
import type { RuntimeEnv } from "../../runtime.js"; import type { RuntimeEnv } from "../../runtime.js";
import { logConfigUpdated } from "../../config/logging.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) { export async function modelsSetImageCommand(modelRaw: string, runtime: RuntimeEnv) {
const updated = await updateConfig((cfg) => { const updated = await updateConfig((cfg) => {
@@ -10,19 +15,16 @@ export async function modelsSetImageCommand(modelRaw: string, runtime: RuntimeEn
if (!nextModels[key]) { if (!nextModels[key]) {
nextModels[key] = {}; nextModels[key] = {};
} }
const existingModel = cfg.agents?.defaults?.imageModel as
| { primary?: string; fallbacks?: string[] }
| undefined;
return { return {
...cfg, ...cfg,
agents: { agents: {
...cfg.agents, ...cfg.agents,
defaults: { defaults: {
...cfg.agents?.defaults, ...cfg.agents?.defaults,
imageModel: { imageModel: mergePrimaryFallbackConfig(
...(existingModel?.fallbacks ? { fallbacks: existingModel.fallbacks } : undefined), cfg.agents?.defaults?.imageModel as unknown as PrimaryFallbackConfig | undefined,
primary: key, { primary: key },
}, ),
models: nextModels, models: nextModels,
}, },
}, },

View File

@@ -1,6 +1,11 @@
import type { RuntimeEnv } from "../../runtime.js"; import type { RuntimeEnv } from "../../runtime.js";
import { logConfigUpdated } from "../../config/logging.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) { export async function modelsSetCommand(modelRaw: string, runtime: RuntimeEnv) {
const updated = await updateConfig((cfg) => { const updated = await updateConfig((cfg) => {
@@ -10,19 +15,16 @@ export async function modelsSetCommand(modelRaw: string, runtime: RuntimeEnv) {
if (!nextModels[key]) { if (!nextModels[key]) {
nextModels[key] = {}; nextModels[key] = {};
} }
const existingModel = cfg.agents?.defaults?.model as
| { primary?: string; fallbacks?: string[] }
| undefined;
return { return {
...cfg, ...cfg,
agents: { agents: {
...cfg.agents, ...cfg.agents,
defaults: { defaults: {
...cfg.agents?.defaults, ...cfg.agents?.defaults,
model: { model: mergePrimaryFallbackConfig(
...(existingModel?.fallbacks ? { fallbacks: existingModel.fallbacks } : undefined), cfg.agents?.defaults?.model as unknown as PrimaryFallbackConfig | undefined,
primary: key, { primary: key },
}, ),
models: nextModels, models: nextModels,
}, },
}, },

View File

@@ -153,6 +153,22 @@ export function resolveKnownAgentId(params: {
return agentId; 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 { modelKey };
export { DEFAULT_MODEL, DEFAULT_PROVIDER }; export { DEFAULT_MODEL, DEFAULT_PROVIDER };