Files
Pyra/tests/unit/test_chat_history.py
T
curo1305 9735a5559e test: add tests for setup wizard personalization and system prompt builder
Cover _USE_CASE_PLUGINS mapping, _suggest_plugins side effects, _build_system_base
output for all name/purpose combinations, and GeneralConfig.purpose round-trip.
Also update CLAUDE.md with the testing workflow rule.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 10:43:20 +02:00

158 lines
5.6 KiB
Python

import pytest
def _make_config():
from pyra.config.schema import PyraConfig, ProviderConfig
return PyraConfig(ai=ProviderConfig(provider_id="lmstudio", model="gemma"))
@pytest.fixture
def history(tmp_pyra_home, monkeypatch):
monkeypatch.setattr("pyra.chat.history.load_context_for_session", lambda: "")
from pyra.chat.history import ConversationHistory
return ConversationHistory(_make_config())
def test_build_for_api_first_message_is_system(history):
msgs = history.build_for_api()
assert msgs[0]["role"] == "system"
def test_build_for_api_system_contains_pyra(history):
msgs = history.build_for_api()
assert "Pyra" in msgs[0]["content"]
def test_build_for_api_includes_memory_context(tmp_pyra_home, monkeypatch):
monkeypatch.setattr(
"pyra.chat.history.load_context_for_session",
lambda: "## Long-term Memory\n\nSome remembered facts.",
)
from pyra.chat.history import ConversationHistory
h = ConversationHistory(_make_config())
msgs = h.build_for_api()
assert "Long-term Memory" in msgs[0]["content"]
def test_add_user_appears_in_api_payload(history):
history.add_user("hello from user")
msgs = history.build_for_api()
user_msgs = [m for m in msgs if m["role"] == "user"]
assert any(m["content"] == "hello from user" for m in user_msgs)
def test_add_assistant_appears_in_api_payload(history):
history.add_assistant("hello from assistant")
msgs = history.build_for_api()
asst_msgs = [m for m in msgs if m["role"] == "assistant"]
assert any(m["content"] == "hello from assistant" for m in asst_msgs)
def test_add_tool_result(history):
history.add_tool_result("call_abc", "tool output")
msgs = history.build_for_api()
tool_msgs = [m for m in msgs if m.get("role") == "tool"]
assert len(tool_msgs) == 1
assert tool_msgs[0]["tool_call_id"] == "call_abc"
assert tool_msgs[0]["content"] == "tool output"
def test_clear_removes_messages(history):
history.add_user("hello")
history.add_assistant("hi")
history.clear()
msgs = history.build_for_api()
assert all(m["role"] == "system" for m in msgs)
def test_trim_to_budget_drops_old_messages():
from pyra.chat.history import _trim_to_budget
msgs = [
{"role": "user", "content": "a" * 4000},
{"role": "assistant", "content": "b" * 4000},
{"role": "user", "content": "new message"},
]
trimmed = _trim_to_budget(list(msgs), 100)
assert len(trimmed) < 3
assert any(m["content"] == "new message" for m in trimmed)
def test_trim_to_budget_no_trim_when_under_budget():
from pyra.chat.history import _trim_to_budget
msgs = [{"role": "user", "content": "short"}]
result = _trim_to_budget(list(msgs), 10000)
assert len(result) == 1
assert result[0]["content"] == "short"
def test_trim_to_budget_empty_list():
from pyra.chat.history import _trim_to_budget
assert _trim_to_budget([], 1000) == []
# ── _build_system_base tests ───────────────────────────────────────────────────
def test_build_system_base_default_identity():
from pyra.chat.history import _build_system_base
result = _build_system_base("User", "Pyra", "")
assert "You are Pyra" in result
assert "User" in result
def test_build_system_base_custom_name_and_assistant():
from pyra.chat.history import _build_system_base
result = _build_system_base("Alice", "Aria", "")
assert "You are Aria" in result
assert "Alice" in result
def test_build_system_base_no_purpose_omits_focus_block():
from pyra.chat.history import _build_system_base
result = _build_system_base("User", "Pyra", "")
assert "primary purpose" not in result
assert "not a general-purpose chatbot" not in result
def test_build_system_base_with_purpose_includes_focus_block():
from pyra.chat.history import _build_system_base
result = _build_system_base("User", "Pyra", "manage my Nextcloud server")
assert "primary purpose" in result
assert "manage my Nextcloud server" in result
assert "not a general-purpose chatbot" in result
def test_build_system_base_always_includes_security_constraints():
from pyra.chat.history import _build_system_base
for purpose in ("", "manage servers"):
result = _build_system_base("User", "Pyra", purpose)
assert "vault" in result
assert "shell commands" in result
def test_build_for_api_uses_config_user_name(tmp_pyra_home, monkeypatch):
monkeypatch.setattr("pyra.chat.history.load_context_for_session", lambda: "")
from pyra.config.schema import PyraConfig, ProviderConfig, GeneralConfig
from pyra.chat.history import ConversationHistory
cfg = PyraConfig(
ai=ProviderConfig(provider_id="lmstudio", model="gemma"),
general=GeneralConfig(user_name="Alice", assistant_name="Aria", purpose=""),
)
h = ConversationHistory(cfg)
system = h.build_for_api()[0]["content"]
assert "Alice" in system
assert "Aria" in system
def test_build_for_api_uses_purpose(tmp_pyra_home, monkeypatch):
monkeypatch.setattr("pyra.chat.history.load_context_for_session", lambda: "")
from pyra.config.schema import PyraConfig, ProviderConfig, GeneralConfig
from pyra.chat.history import ConversationHistory
cfg = PyraConfig(
ai=ProviderConfig(provider_id="lmstudio", model="gemma"),
general=GeneralConfig(purpose="manage my home server"),
)
h = ConversationHistory(cfg)
system = h.build_for_api()[0]["content"]
assert "manage my home server" in system
assert "primary purpose" in system