honcho/tests/deriver/test_prompts.py

93 lines
3.1 KiB
Python

from collections.abc import AsyncGenerator, Generator
from unittest.mock import patch
import pytest
from pydantic import ValidationError
from src.deriver.prompts import (
estimate_deriver_prompt_tokens,
estimate_minimal_deriver_prompt_tokens,
minimal_deriver_prompt,
)
from src.utils.representation import PromptRepresentation
@pytest.fixture(autouse=True)
async def clean_queue_tables() -> AsyncGenerator[None, None]:
"""Prompt-only tests do not need queue table cleanup."""
yield
@pytest.fixture(autouse=True)
def mock_tracked_db() -> Generator[None, None, None]:
"""Prompt-only tests do not need tracked_db patching."""
yield
def test_minimal_deriver_prompt_includes_custom_instructions_when_present() -> None:
prompt = minimal_deriver_prompt(
peer_id="alice",
messages="alice: hello",
custom_instructions="Prefer concrete timeline facts.",
)
assert "CUSTOM INSTRUCTIONS:" in prompt
assert "Prefer concrete timeline facts." in prompt
def test_minimal_deriver_prompt_omits_custom_instructions_when_absent() -> None:
prompt = minimal_deriver_prompt(
peer_id="alice",
messages="alice: hello",
custom_instructions=None,
)
assert "CUSTOM INSTRUCTIONS:" not in prompt
def test_minimal_deriver_prompt_describes_explicit_json_object_shape() -> None:
prompt = minimal_deriver_prompt(
peer_id="alice",
messages="alice: I just had my 25th birthday",
custom_instructions=None,
)
assert '"explicit": [{"content": "fact 1"}' in prompt
assert 'Each item in "explicit" must be an object with a "content" field' in prompt
assert "not a bare string" in prompt
with pytest.raises(ValidationError):
PromptRepresentation.model_validate_json(
'{"explicit": ["alice is 25 years old"]}'
)
assert PromptRepresentation.model_validate_json(
'{"explicit": [{"content": "alice is 25 years old"}]}'
).explicit[0].content == "alice is 25 years old"
explicit_schema_description = PromptRepresentation.model_json_schema()["properties"][
"explicit"
]["description"]
assert '{"content": "The user is 25 years old"}' in explicit_schema_description
assert "['The user is 25 years old'" not in explicit_schema_description
def test_estimate_deriver_prompt_tokens_increases_with_custom_instructions() -> None:
base_tokens = estimate_minimal_deriver_prompt_tokens()
custom_tokens = estimate_deriver_prompt_tokens(
"Prefer explicit facts with absolute dates and keep the subject precise."
)
assert custom_tokens > base_tokens
def test_estimate_deriver_prompt_tokens_propagates_token_estimation_errors() -> None:
estimate_minimal_deriver_prompt_tokens.cache_clear()
with patch(
"src.deriver.prompts.estimate_tokens",
side_effect=RuntimeError("tokenizer unavailable"),
):
with pytest.raises(RuntimeError, match="tokenizer unavailable"):
estimate_deriver_prompt_tokens(None)
with pytest.raises(RuntimeError, match="tokenizer unavailable"):
estimate_deriver_prompt_tokens("Prefer concrete facts.")