mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-09-04 10:11:46 +03:00
refactor(models): unify preset names
This commit is contained in:
@@ -361,3 +361,15 @@ def test_resolver_mutates_only_its_default_selection() -> None:
|
||||
assert resolver.model_preset is None
|
||||
assert initial.model == "base-model"
|
||||
assert initial.context_window_tokens == 10_000
|
||||
|
||||
|
||||
def test_resolver_preserves_canonical_preset_name_for_case_insensitive_input() -> None:
|
||||
resolver = ModelRuntimeResolver(
|
||||
_runtime(),
|
||||
model_presets={"Deep Research": ModelPresetConfig(model="deep-model")},
|
||||
)
|
||||
|
||||
selected = resolver.select_preset("deep research")
|
||||
|
||||
assert selected.model == "deep-model"
|
||||
assert selected.model_preset == "Deep Research"
|
||||
|
||||
@@ -33,14 +33,14 @@ def _provider(default_model: str, max_tokens: int = 123) -> MagicMock:
|
||||
return provider
|
||||
|
||||
|
||||
def _make_loop(tmp_path, *, preset_snapshot_loader=None) -> AgentLoop:
|
||||
def _make_loop(tmp_path, *, preset_snapshot_loader=None, model_presets=None) -> AgentLoop:
|
||||
return AgentLoop(
|
||||
bus=MessageBus(),
|
||||
provider=_provider("base-model", max_tokens=123),
|
||||
workspace=tmp_path,
|
||||
model="base-model",
|
||||
context_window_tokens=1000,
|
||||
model_presets={
|
||||
model_presets=model_presets or {
|
||||
"default": ModelPresetConfig(
|
||||
model="base-model",
|
||||
max_tokens=123,
|
||||
@@ -106,6 +106,24 @@ async def test_model_command_switches_preset(tmp_path) -> None:
|
||||
assert status is not None and "openai/gpt-4.1" in status.content
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_command_accepts_canonical_names_with_spaces(tmp_path) -> None:
|
||||
loop = _make_loop(
|
||||
tmp_path,
|
||||
model_presets={
|
||||
"default": ModelPresetConfig(model="base-model"),
|
||||
"Deep Research": ModelPresetConfig(model="deep-model"),
|
||||
},
|
||||
)
|
||||
|
||||
out = await cmd_model(
|
||||
_ctx(loop, "/model deep research", args="deep research"),
|
||||
)
|
||||
|
||||
assert "Switched model preset to `Deep Research`." in out.content
|
||||
assert _saved_model_preset(loop) == "Deep Research"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_command_switches_back_to_default(tmp_path) -> None:
|
||||
loop = _make_loop(tmp_path)
|
||||
|
||||
@@ -275,6 +275,30 @@ def test_model_presets_accepts_camel_case_root_key() -> None:
|
||||
assert config.model_presets["fast"].provider == "openai"
|
||||
|
||||
|
||||
def test_legacy_model_preset_label_is_ignored() -> None:
|
||||
config = Config.model_validate({
|
||||
"modelPresets": {
|
||||
"gpt-5-6-sol": {
|
||||
"label": "Codex",
|
||||
"model": "openai-codex/gpt-5.6-luna",
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
assert set(config.model_presets) == {"gpt-5-6-sol"}
|
||||
assert "label" not in config.model_presets["gpt-5-6-sol"].model_dump()
|
||||
|
||||
|
||||
def test_model_preset_names_are_unique_ignoring_case() -> None:
|
||||
with pytest.raises(ValueError, match="unique ignoring case"):
|
||||
Config.model_validate({
|
||||
"modelPresets": {
|
||||
"Fast": {"model": "openai/gpt-4.1-mini"},
|
||||
"fast": {"model": "openai/gpt-4.1"},
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
def test_model_presets_serializes_with_camel_case_root_key() -> None:
|
||||
config = Config.model_validate({
|
||||
"model_presets": {
|
||||
|
||||
@@ -236,7 +236,7 @@ def _dynamic_provider_config(
|
||||
return Config.model_validate(raw_config)
|
||||
|
||||
|
||||
def test_create_model_configuration_writes_label_without_changing_call_order(
|
||||
def test_create_model_configuration_accepts_legacy_label_without_changing_call_order(
|
||||
tmp_path,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
@@ -260,11 +260,10 @@ def test_create_model_configuration_writes_label_without_changing_call_order(
|
||||
assert payload["agent"]["model"] == "openai/gpt-4o"
|
||||
assert payload["created_model_preset"] == "fast-writing"
|
||||
rows = {row["name"]: row for row in payload["model_presets"]}
|
||||
assert rows["fast-writing"]["label"] == "Fast writing"
|
||||
assert rows["fast-writing"]["label"] == "fast-writing"
|
||||
|
||||
saved = load_config(config_path)
|
||||
assert saved.agents.defaults.model_preset is None
|
||||
assert saved.model_presets["fast-writing"].label == "Fast writing"
|
||||
assert saved.model_presets["fast-writing"].model == "openai/gpt-4.1-mini"
|
||||
assert saved.model_presets["fast-writing"].provider == "openai"
|
||||
|
||||
@@ -279,6 +278,40 @@ def test_create_model_configuration_writes_label_without_changing_call_order(
|
||||
assert duplicate.value.status == 409
|
||||
|
||||
|
||||
def test_create_model_configuration_preserves_canonical_name(
|
||||
tmp_path,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
config_path = tmp_path / "config.json"
|
||||
config = Config()
|
||||
config.providers.openai.api_key = "sk-test"
|
||||
save_config(config, config_path)
|
||||
monkeypatch.setattr("nanobot.config.loader._current_config_path", config_path)
|
||||
|
||||
payload = create_model_configuration(
|
||||
{
|
||||
"name": ["Fast Writing"],
|
||||
"provider": ["openai"],
|
||||
"model": ["openai/gpt-4.1-mini"],
|
||||
}
|
||||
)
|
||||
|
||||
assert payload["created_model_preset"] == "Fast Writing"
|
||||
rows = {row["name"]: row for row in payload["model_presets"]}
|
||||
assert rows["Fast Writing"]["label"] == "Fast Writing"
|
||||
assert "Fast Writing" in load_config(config_path).model_presets
|
||||
|
||||
with pytest.raises(WebUISettingsError) as duplicate:
|
||||
create_model_configuration(
|
||||
{
|
||||
"name": ["fast writing"],
|
||||
"provider": ["openai"],
|
||||
"model": ["openai/gpt-4.1-mini"],
|
||||
}
|
||||
)
|
||||
assert duplicate.value.status == 409
|
||||
|
||||
|
||||
def test_create_model_configuration_accepts_dynamic_custom_provider(
|
||||
tmp_path,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
@@ -353,7 +386,6 @@ def test_update_model_configuration_edits_named_preset_without_selecting(
|
||||
config = Config()
|
||||
config.providers.openai.api_key = "sk-test"
|
||||
config.model_presets["codex"] = ModelPresetConfig(
|
||||
label="Old Codex",
|
||||
provider="openai",
|
||||
model="openai/gpt-4.1",
|
||||
)
|
||||
@@ -382,7 +414,6 @@ def test_update_model_configuration_edits_named_preset_without_selecting(
|
||||
assert payload["agent"]["model"] == "anthropic/claude-opus-4-5"
|
||||
saved = load_config(config_path)
|
||||
assert saved.agents.defaults.model_preset is None
|
||||
assert saved.model_presets["codex"].label == "Codex"
|
||||
assert saved.model_presets["codex"].provider == "openai_codex"
|
||||
assert saved.model_presets["codex"].model == "openai-codex/gpt-5.5"
|
||||
|
||||
@@ -834,7 +865,6 @@ def test_update_model_configuration_preserves_custom_context_windows(
|
||||
config_path = tmp_path / "config.json"
|
||||
config = Config()
|
||||
config.model_presets["codex"] = ModelPresetConfig(
|
||||
label="Codex",
|
||||
provider="openai",
|
||||
model="openai/gpt-4.1",
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user