feat(agent): make model presets session-scoped (#4866)

This commit is contained in:
chengyongru
2026-07-23 00:38:49 +08:00
committed by GitHub
parent 66690fdb0c
commit c22efb5f7a
41 changed files with 1140 additions and 155 deletions
+22
View File
@@ -4,11 +4,14 @@ import os
from datetime import datetime
from pathlib import Path
import pytest
import nanobot.webui.session_list_index as session_list_index
from nanobot.cron.session_turns import CRON_HISTORY_META
from nanobot.session.automation_turns import AUTOMATION_HISTORY_META
from nanobot.session.history_visibility import HIDDEN_HISTORY_META
from nanobot.session.manager import SessionManager
from nanobot.session.model_selection import SESSION_MODEL_PRESET_METADATA_KEY
def test_webui_session_list_reuses_valid_index_without_scanning_files(
@@ -17,10 +20,12 @@ def test_webui_session_list_reuses_valid_index_without_scanning_files(
) -> None:
manager = SessionManager(tmp_path)
session = manager.get_or_create("websocket:indexed")
session.metadata[SESSION_MODEL_PRESET_METADATA_KEY] = "fast"
session.add_message("user", "indexed preview")
manager.save(session)
assert list_webui_sessions(manager)[0]["preview"] == "indexed preview"
assert list_webui_sessions(manager)[0]["model_preset"] == "fast"
def fail_scan(session_manager: SessionManager, path: Path) -> None:
raise AssertionError(f"unexpected session file scan: {path}")
@@ -31,6 +36,23 @@ def test_webui_session_list_reuses_valid_index_without_scanning_files(
assert rows[0]["key"] == "websocket:indexed"
assert rows[0]["preview"] == "indexed preview"
assert rows[0]["model_preset"] == "fast"
def test_webui_session_list_rejects_invalid_internal_model_preset_metadata(
tmp_path: Path,
) -> None:
manager = SessionManager(tmp_path)
session = manager.get_or_create("websocket:custom-metadata")
session.metadata["model_preset"] = 7
session.metadata[SESSION_MODEL_PRESET_METADATA_KEY] = {"invalid": True}
session.add_message("user", "custom metadata")
manager.save(session)
with pytest.raises(ValueError, match="session model preset must be a non-empty string"):
list_webui_sessions(manager)
assert manager.get_or_create(session.key).metadata["model_preset"] == 7
def test_webui_session_list_rescans_only_changed_file(tmp_path: Path, monkeypatch) -> None:
+20
View File
@@ -464,6 +464,26 @@ def test_settings_payload_includes_dynamic_custom_provider(
assert providers[DYNAMIC_PROVIDER_NAME]["api_base"] == DYNAMIC_PROVIDER_API_BASE
def test_settings_payload_resolves_provider_for_each_auto_preset(
tmp_path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
config_path = tmp_path / "config.json"
config = _dynamic_provider_config()
config.model_presets["fast"] = ModelPresetConfig(
provider="auto",
model=f"{DYNAMIC_PROVIDER_NAME}/gpt-4",
)
save_config(config, config_path)
monkeypatch.setattr("nanobot.config.loader._current_config_path", config_path)
payload = settings_payload()
presets = {row["name"]: row for row in payload["model_presets"]}
assert presets["fast"]["provider"] == "auto"
assert presets["fast"]["resolved_provider"] == DYNAMIC_PROVIDER_NAME
def test_settings_payload_groups_opencode_compatibility_alias(tmp_path, monkeypatch) -> None:
config_path = tmp_path / "config.json"
save_config(Config(), config_path)