chore: remove expired v0.3.1 compatibility shims (#5106)
This commit is contained in:
@@ -65,7 +65,7 @@ def test_save_uses_new_path_not_lossy(tmp_path: Path, monkeypatch) -> None:
|
||||
assert lossy_path.read_text(encoding="utf-8") == stale_lossy
|
||||
|
||||
|
||||
def test_load_falls_back_to_lossy_path(tmp_path: Path, monkeypatch) -> None:
|
||||
def test_load_ignores_legacy_lossy_path(tmp_path: Path, monkeypatch) -> None:
|
||||
sm = _manager(tmp_path, monkeypatch)
|
||||
key = "telegram:legacy:lossy"
|
||||
lossy_path = sm._get_legacy_lossy_path(key)
|
||||
@@ -73,49 +73,23 @@ def test_load_falls_back_to_lossy_path(tmp_path: Path, monkeypatch) -> None:
|
||||
|
||||
session = sm._load(key)
|
||||
|
||||
assert session is not None
|
||||
assert session.metadata == {"source": "test"}
|
||||
assert session.messages[0]["content"] == "loaded from lossy"
|
||||
assert session is None
|
||||
assert lossy_path.exists()
|
||||
assert not sm._get_session_path(key).exists()
|
||||
|
||||
|
||||
def test_load_migrates_lossy_to_new_path(tmp_path: Path, monkeypatch) -> None:
|
||||
def test_load_ignores_legacy_global_path(tmp_path: Path, monkeypatch) -> None:
|
||||
sm = _manager(tmp_path, monkeypatch)
|
||||
key = "telegram:migrate:lossy"
|
||||
key = "telegram:legacy:global"
|
||||
new_path = sm._get_session_path(key)
|
||||
lossy_path = sm._get_legacy_lossy_path(key)
|
||||
_write_session_file(lossy_path, key, "migrate me")
|
||||
legacy_path = sm._get_legacy_session_path(key)
|
||||
_write_session_file(legacy_path, key, "loaded from global")
|
||||
|
||||
session = sm._load(key)
|
||||
|
||||
assert session is not None
|
||||
assert session.messages[0]["content"] == "migrate me"
|
||||
assert new_path.exists()
|
||||
assert not lossy_path.exists()
|
||||
|
||||
|
||||
def test_load_does_not_migrate_lossy_path_for_different_stored_key(
|
||||
tmp_path: Path,
|
||||
monkeypatch,
|
||||
) -> None:
|
||||
sm = _manager(tmp_path, monkeypatch)
|
||||
first_key = "telegram:a_b"
|
||||
second_key = "telegram:a:b"
|
||||
lossy_path = sm._get_legacy_lossy_path(first_key)
|
||||
assert lossy_path == sm._get_legacy_lossy_path(second_key)
|
||||
_write_session_file(lossy_path, first_key, "belongs to first")
|
||||
|
||||
loaded_second = sm._load(second_key)
|
||||
|
||||
assert loaded_second is None
|
||||
assert lossy_path.exists()
|
||||
assert not sm._get_session_path(second_key).exists()
|
||||
|
||||
loaded_first = sm._load(first_key)
|
||||
|
||||
assert loaded_first is not None
|
||||
assert loaded_first.messages[0]["content"] == "belongs to first"
|
||||
assert sm._get_session_path(first_key).exists()
|
||||
assert not lossy_path.exists()
|
||||
assert session is None
|
||||
assert legacy_path.exists()
|
||||
assert not new_path.exists()
|
||||
|
||||
|
||||
def test_safe_key_is_lossy() -> None:
|
||||
|
||||
@@ -788,35 +788,6 @@ def test_discover_plugins_skips_names_outside_enabled_set():
|
||||
assert loaded == []
|
||||
|
||||
|
||||
def test_discover_plugins_warns_once_for_legacy_entry_points():
|
||||
from nanobot.channels.registry import _warn_legacy_channel_entry_points, discover_plugins
|
||||
|
||||
legacy_entry_points = [SimpleNamespace(name="z-old"), SimpleNamespace(name="a-old")]
|
||||
_warn_legacy_channel_entry_points.cache_clear()
|
||||
try:
|
||||
with (
|
||||
patch(
|
||||
"nanobot.channels.registry.entry_points",
|
||||
return_value=legacy_entry_points,
|
||||
) as metadata_entry_points,
|
||||
patch("nanobot.channels.registry._channel_package_names", return_value=[]),
|
||||
patch("nanobot.channels.registry.logger.warning") as warning,
|
||||
):
|
||||
discover_plugins()
|
||||
discover_plugins()
|
||||
finally:
|
||||
_warn_legacy_channel_entry_points.cache_clear()
|
||||
|
||||
metadata_entry_points.assert_called_once_with(group="nanobot.channels")
|
||||
warning.assert_called_once_with(
|
||||
"Legacy channel entry points were detected but will not be loaded: {}. "
|
||||
"The '{}' entry-point group is no longer supported; use a built-in channel or "
|
||||
"migrate it into nanobot/channels/<channel>/.",
|
||||
"a-old, z-old",
|
||||
"nanobot.channels",
|
||||
)
|
||||
|
||||
|
||||
def test_channel_manifest_rejects_invalid_dependency_metadata():
|
||||
with pytest.raises(TypeError, match="tuple of requirements"):
|
||||
ChannelPlugin(
|
||||
|
||||
@@ -1728,17 +1728,6 @@ def test_agent_workspace_override_wins_over_config_workspace(mock_agent_runtime,
|
||||
assert passed_config.workspace_path == workspace_path
|
||||
|
||||
|
||||
def test_agent_hints_about_deprecated_memory_window(mock_agent_runtime, tmp_path):
|
||||
config_file = tmp_path / "config.json"
|
||||
config_file.write_text(json.dumps({"agents": {"defaults": {"memoryWindow": 42}}}))
|
||||
|
||||
result = runner.invoke(app, ["agent", "-m", "hello", "-c", str(config_file)])
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert "memoryWindow" in result.stdout
|
||||
assert "no longer used" in result.stdout
|
||||
|
||||
|
||||
def test_heartbeat_retains_recent_messages_by_default():
|
||||
config = Config()
|
||||
|
||||
|
||||
@@ -96,22 +96,17 @@ def test_onboard_does_not_crash_with_legacy_memory_window(tmp_path, monkeypatch)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("field_name", ["maxMessages", "max_messages"])
|
||||
def test_load_config_warns_and_ignores_legacy_max_messages(tmp_path, field_name) -> None:
|
||||
def test_load_config_ignores_legacy_max_messages(tmp_path, field_name) -> None:
|
||||
config_path = tmp_path / "config.json"
|
||||
config_path.write_text(
|
||||
json.dumps({"agents": {"defaults": {field_name: 25, "maxTokens": 1234}}}),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
with patch("nanobot.config.loader.logger.warning") as warning:
|
||||
config = load_config(config_path)
|
||||
config = load_config(config_path)
|
||||
|
||||
assert config.agents.defaults.max_tokens == 1234
|
||||
assert not hasattr(config.agents.defaults, "max_messages")
|
||||
warning.assert_called_once()
|
||||
message = warning.call_args.args[0]
|
||||
assert "legacy and ignored" in message
|
||||
assert "next version" in message
|
||||
|
||||
|
||||
def test_save_config_drops_legacy_max_messages(tmp_path) -> None:
|
||||
@@ -121,8 +116,7 @@ def test_save_config_drops_legacy_max_messages(tmp_path) -> None:
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
with patch("nanobot.config.loader.logger.warning"):
|
||||
config = load_config(config_path)
|
||||
config = load_config(config_path)
|
||||
save_config(config, config_path)
|
||||
saved = json.loads(config_path.read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
@@ -52,3 +52,22 @@ def test_dream_config_uses_model_override_name_and_accepts_legacy_model() -> Non
|
||||
assert cfg.model_override == "openrouter/sonnet"
|
||||
assert dumped["modelOverride"] == "openrouter/sonnet"
|
||||
assert "model" not in dumped
|
||||
|
||||
|
||||
def test_dream_config_ignores_retired_noop_fields() -> None:
|
||||
cfg = DreamConfig.model_validate(
|
||||
{
|
||||
"maxBatchSize": 99,
|
||||
"maxIterations": 99,
|
||||
"annotateLineAges": False,
|
||||
}
|
||||
)
|
||||
|
||||
dumped = cfg.model_dump(by_alias=True)
|
||||
|
||||
assert not hasattr(cfg, "max_batch_size")
|
||||
assert not hasattr(cfg, "max_iterations")
|
||||
assert not hasattr(cfg, "annotate_line_ages")
|
||||
assert "maxBatchSize" not in dumped
|
||||
assert "maxIterations" not in dumped
|
||||
assert "annotateLineAges" not in dumped
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
"""Regression tests for legacy-stem session handling."""
|
||||
"""Tests for retired legacy session storage paths."""
|
||||
|
||||
import json
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
@@ -6,15 +7,11 @@ from pathlib import Path
|
||||
from nanobot.session.manager import SessionManager
|
||||
|
||||
|
||||
def test_list_sessions_repairs_corrupt_legacy_stem(tmp_path: Path, monkeypatch) -> None:
|
||||
monkeypatch.setattr(
|
||||
"nanobot.session.manager.get_legacy_sessions_dir",
|
||||
lambda: tmp_path / "legacy_sessions",
|
||||
)
|
||||
def test_list_sessions_ignores_legacy_stem(tmp_path: Path) -> None:
|
||||
manager = SessionManager(tmp_path / "workspace")
|
||||
|
||||
# Simulate a legacy lossy-path filename (telegram_12345.jsonl) with a corrupt
|
||||
# first line that triggers the repair branch in list_sessions.
|
||||
# A legacy lossy-path filename must not be treated as current session storage,
|
||||
# even when the file contains otherwise recoverable records.
|
||||
legacy_stem = "telegram_12345"
|
||||
corrupt_path = manager.sessions_dir / f"{legacy_stem}.jsonl"
|
||||
corrupt_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
@@ -24,7 +21,6 @@ def test_list_sessions_repairs_corrupt_legacy_stem(tmp_path: Path, monkeypatch)
|
||||
"created_at": datetime(2025, 1, 1).isoformat(),
|
||||
"updated_at": datetime(2025, 1, 1).isoformat(),
|
||||
})
|
||||
# Corrupt line followed by valid message
|
||||
corrupt_path.write_text(
|
||||
metadata + "\n{INVALID JSON LINE\n"
|
||||
+ json.dumps({"role": "user", "content": "recoverable message"}) + "\n",
|
||||
@@ -33,14 +29,11 @@ def test_list_sessions_repairs_corrupt_legacy_stem(tmp_path: Path, monkeypatch)
|
||||
|
||||
sessions = manager.list_sessions()
|
||||
|
||||
# BUG: repair fails because _repair re-encodes the fallback_key via
|
||||
# _get_session_path, producing a base64 stem that doesn't match the
|
||||
# actual legacy filename. The session is silently dropped.
|
||||
assert len(sessions) == 1, f"Expected 1 session, got {len(sessions)}"
|
||||
assert sessions[0]["key"] == "telegram:12345"
|
||||
assert sessions == []
|
||||
assert corrupt_path.exists()
|
||||
|
||||
|
||||
def test_read_session_methods_fall_back_to_legacy_lossy_stem(
|
||||
def test_read_session_methods_ignore_legacy_lossy_stem(
|
||||
tmp_path: Path,
|
||||
monkeypatch,
|
||||
) -> None:
|
||||
@@ -69,8 +62,5 @@ def test_read_session_methods_fall_back_to_legacy_lossy_stem(
|
||||
metadata_result = manager.read_session_metadata(key)
|
||||
file_result = manager.read_session_file(key)
|
||||
|
||||
assert metadata_result is not None
|
||||
assert metadata_result["metadata"] == metadata["metadata"]
|
||||
assert file_result is not None
|
||||
assert file_result["metadata"] == metadata["metadata"]
|
||||
assert file_result["messages"] == []
|
||||
assert metadata_result is None
|
||||
assert file_result is None
|
||||
|
||||
@@ -98,6 +98,20 @@ def test_webui_session_list_drops_deleted_index_rows(tmp_path: Path) -> None:
|
||||
assert list_webui_sessions(manager) == []
|
||||
|
||||
|
||||
def test_webui_session_list_ignores_legacy_stem(tmp_path: Path) -> None:
|
||||
manager = SessionManager(tmp_path)
|
||||
legacy_path = manager.sessions_dir / "websocket_legacy.jsonl"
|
||||
legacy_path.write_text(
|
||||
'{"_type":"metadata","key":"websocket:legacy",'
|
||||
'"created_at":"2025-01-01T00:00:00",'
|
||||
'"updated_at":"2025-01-01T00:00:00","metadata":{}}\n',
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
assert list_webui_sessions(manager) == []
|
||||
assert legacy_path.exists()
|
||||
|
||||
|
||||
def test_webui_session_list_skips_cron_internal_user_preview(tmp_path: Path) -> None:
|
||||
manager = SessionManager(tmp_path)
|
||||
session = manager.get_or_create("websocket:cron-preview")
|
||||
|
||||
Reference in New Issue
Block a user