fix(models): support atomic preset renames

This commit is contained in:
Xubin Ren
2026-08-16 11:50:56 +08:00
parent 3dc38f6396
commit c15e6f2a37
12 changed files with 203 additions and 49 deletions
@@ -3308,7 +3308,7 @@ async def test_settings_api_returns_safe_subset_and_updates_whitelist(
"settings.model_configuration.update",
{
"name": "fast-writing",
"label": "Codex",
"new_name": "Codex",
"provider": "openai",
"model": "openai/gpt-5.5",
},
@@ -3320,24 +3320,24 @@ async def test_settings_api_returns_safe_subset_and_updates_whitelist(
updated_presets = {
preset["name"]: preset for preset in updated_preset_body["model_presets"]
}
assert updated_presets["fast-writing"]["label"] == "fast-writing"
assert updated_presets["Codex"]["label"] == "Codex"
call_order_updated = await _webui_mutate(
webui_client,
"settings.model_call_order.update",
{"order": ["fast-writing", "deep"]},
{"order": ["Codex", "deep"]},
)
assert call_order_updated.status_code == 200
call_order_body = call_order_updated.json()
assert call_order_body["agent"]["model_preset"] == "fast-writing"
assert call_order_body["agent"]["model_preset"] == "Codex"
assert call_order_body["agent"]["model"] == "openai/gpt-5.5"
assert call_order_body["model_call_order"] == ["fast-writing", "deep"]
assert call_order_body["model_call_order"] == ["Codex", "deep"]
duplicate_preset = await _webui_mutate(
webui_client,
"settings.model_configuration.create",
{
"label": "Fast writing",
"name": "codex",
"provider": "openai",
"model": "openai/gpt-4.1-mini",
},
@@ -3435,10 +3435,10 @@ async def test_settings_api_returns_safe_subset_and_updates_whitelist(
saved = load_config(config_path)
assert saved.agents.defaults.model == "atomic_chat/test"
assert saved.agents.defaults.provider == "atomic_chat"
assert saved.agents.defaults.model_preset == "fast-writing"
assert saved.agents.defaults.model_preset == "Codex"
assert saved.agents.defaults.fallback_models == ["deep"]
assert saved.model_presets["fast-writing"].model == "openai/gpt-5.5"
assert saved.model_presets["fast-writing"].provider == "openai"
assert saved.model_presets["Codex"].model == "openai/gpt-5.5"
assert saved.model_presets["Codex"].provider == "openai"
assert saved.agents.defaults.timezone == "Asia/Shanghai"
assert saved.agents.defaults.bot_name == "nanobot"
assert saved.agents.defaults.bot_icon == "🐈"
+40 -2
View File
@@ -792,9 +792,40 @@ def _model_configuration_name(value: str) -> str:
return name
def _model_configuration_name_exists(config: Config, name: str) -> bool:
def _model_configuration_name_exists(
config: Config,
name: str,
*,
exclude: str | None = None,
) -> bool:
normalized = name.casefold()
return any(existing.casefold() == normalized for existing in config.model_presets)
return any(
existing != exclude and existing.casefold() == normalized
for existing in config.model_presets
)
def _rename_model_configuration(config: Config, old_name: str, new_name: str) -> bool:
"""Rename one preset and every config reference to it."""
if old_name == new_name:
return False
if _model_configuration_name_exists(config, new_name, exclude=old_name):
raise WebUISettingsError("configuration already exists", status=409)
config.model_presets = {
(new_name if name == old_name else name): preset
for name, preset in config.model_presets.items()
}
defaults = config.agents.defaults
if defaults.model_preset == old_name:
defaults.model_preset = new_name
defaults.fallback_models = [
new_name if fallback == old_name else fallback
for fallback in defaults.fallback_models
]
if defaults.dream.model_override == old_name:
defaults.dream.model_override = new_name
return True
def _custom_provider_key(config: Config, display_name: str) -> str:
@@ -1139,6 +1170,13 @@ def update_model_configuration(
raise WebUISettingsError("unknown model configuration")
changed = False
new_name_value = query_first_alias(query, "new_name", "newName")
if new_name_value is not None:
new_name = _model_configuration_name(new_name_value)
changed = _rename_model_configuration(config, name, new_name) or changed
name = new_name
preset = config.model_presets[name]
model = query_first(query, "model")
if model is not None:
model = model.strip()