mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-09-03 01:31:47 +03:00
fix(webui): activate existing model presets safely
This commit is contained in:
@@ -269,7 +269,11 @@ def update_model_call_order(
|
|||||||
config_path: Path | None = None,
|
config_path: Path | None = None,
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
config = _load_settings_config(config_path)
|
config = _load_settings_config(config_path)
|
||||||
if models.update_model_call_order(config, query):
|
if models.update_model_call_order(
|
||||||
|
config,
|
||||||
|
query,
|
||||||
|
oauth_status=_oauth_provider_status,
|
||||||
|
):
|
||||||
_save_settings_config(config, config_path)
|
_save_settings_config(config, config_path)
|
||||||
return settings_payload(config_path=config_path)
|
return settings_payload(config_path=config_path)
|
||||||
|
|
||||||
|
|||||||
@@ -1312,7 +1312,12 @@ def update_model_configuration(
|
|||||||
return changed
|
return changed
|
||||||
|
|
||||||
|
|
||||||
def update_model_call_order(config: Config, query: QueryParams) -> bool:
|
def update_model_call_order(
|
||||||
|
config: Config,
|
||||||
|
query: QueryParams,
|
||||||
|
*,
|
||||||
|
oauth_status: OAuthStatusReader,
|
||||||
|
) -> bool:
|
||||||
raw_order = query_first_alias(query, "order", "presetNames")
|
raw_order = query_first_alias(query, "order", "presetNames")
|
||||||
if raw_order is None:
|
if raw_order is None:
|
||||||
raise WebUISettingsError("model call order is required")
|
raise WebUISettingsError("model call order is required")
|
||||||
@@ -1331,15 +1336,16 @@ def update_model_call_order(config: Config, query: QueryParams) -> bool:
|
|||||||
raise WebUISettingsError("model call order must contain at least one preset")
|
raise WebUISettingsError("model call order must contain at least one preset")
|
||||||
|
|
||||||
normalized_order = [cast(str, name).strip() for name in cast(list[object], order)]
|
normalized_order = [cast(str, name).strip() for name in cast(list[object], order)]
|
||||||
|
unknown = [name for name in normalized_order if name not in config.model_presets]
|
||||||
|
if unknown:
|
||||||
|
raise WebUISettingsError(f"unknown model preset: {unknown[0]}")
|
||||||
|
|
||||||
_, editable = _model_call_order_state(config)
|
_, editable = _model_call_order_state(config)
|
||||||
if not editable:
|
if not editable and _legacy_model_configuration_migratable(config, oauth_status):
|
||||||
raise WebUISettingsError(
|
raise WebUISettingsError(
|
||||||
"convert the existing model configuration to presets first",
|
"convert the existing model configuration to presets first",
|
||||||
status=409,
|
status=409,
|
||||||
)
|
)
|
||||||
unknown = [name for name in normalized_order if name not in config.model_presets]
|
|
||||||
if unknown:
|
|
||||||
raise WebUISettingsError(f"unknown model preset: {unknown[0]}")
|
|
||||||
|
|
||||||
defaults = config.agents.defaults
|
defaults = config.agents.defaults
|
||||||
fallback_models: list[FallbackCandidate] = list(normalized_order[1:])
|
fallback_models: list[FallbackCandidate] = list(normalized_order[1:])
|
||||||
|
|||||||
@@ -592,7 +592,7 @@ def test_update_model_call_order_sets_primary_and_fallbacks(
|
|||||||
assert saved.agents.defaults.fallback_models == ["primary"]
|
assert saved.agents.defaults.fallback_models == ["primary"]
|
||||||
|
|
||||||
|
|
||||||
def test_update_model_call_order_requires_named_primary(
|
def test_update_model_call_order_activates_existing_named_preset(
|
||||||
tmp_path,
|
tmp_path,
|
||||||
monkeypatch: pytest.MonkeyPatch,
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
) -> None:
|
) -> None:
|
||||||
@@ -602,11 +602,36 @@ def test_update_model_call_order_requires_named_primary(
|
|||||||
save_config(config, config_path)
|
save_config(config, config_path)
|
||||||
monkeypatch.setattr("nanobot.config.loader._current_config_path", config_path)
|
monkeypatch.setattr("nanobot.config.loader._current_config_path", config_path)
|
||||||
|
|
||||||
|
payload = update_model_call_order({"order": [json.dumps(["backup"])]})
|
||||||
|
|
||||||
|
assert payload["model_call_order"] == ["backup"]
|
||||||
|
assert payload["model_call_order_editable"] is True
|
||||||
|
assert load_config(config_path).agents.defaults.model_preset == "backup"
|
||||||
|
|
||||||
|
|
||||||
|
def test_update_model_call_order_preserves_real_legacy_configuration(
|
||||||
|
tmp_path,
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
) -> None:
|
||||||
|
config_path = tmp_path / "config.json"
|
||||||
|
config = Config()
|
||||||
|
config.providers.openai.api_key = "sk-test"
|
||||||
|
config.agents.defaults.model = "openai/gpt-4o"
|
||||||
|
config.agents.defaults.provider = "openai"
|
||||||
|
config.model_presets["backup"] = ModelPresetConfig(
|
||||||
|
model="openai/gpt-4.1-mini",
|
||||||
|
provider="openai",
|
||||||
|
)
|
||||||
|
save_config(config, config_path)
|
||||||
|
monkeypatch.setattr("nanobot.config.loader._current_config_path", config_path)
|
||||||
|
|
||||||
with pytest.raises(WebUISettingsError) as error:
|
with pytest.raises(WebUISettingsError) as error:
|
||||||
update_model_call_order({"order": [json.dumps(["backup"])]})
|
update_model_call_order({"order": [json.dumps(["backup"])]})
|
||||||
|
|
||||||
assert error.value.status == 409
|
assert error.value.status == 409
|
||||||
assert load_config(config_path).agents.defaults.model_preset is None
|
saved = load_config(config_path)
|
||||||
|
assert saved.agents.defaults.model_preset is None
|
||||||
|
assert saved.agents.defaults.model == "openai/gpt-4o"
|
||||||
|
|
||||||
|
|
||||||
def test_migrate_model_configurations_preserves_legacy_chain(
|
def test_migrate_model_configurations_preserves_legacy_chain(
|
||||||
|
|||||||
Reference in New Issue
Block a user