Spaces:
Sleeping
Sleeping
File size: 4,364 Bytes
7fedbc5 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | from __future__ import annotations
from sqlalchemy import select
from app.characters.memory_generator import GeneratedMemory, build_prompt, generate_and_store
from app.db import SessionLocal
from app.models.character import Character, CharacterState
from app.models.memory import Memory, MemoryScope, MemoryType
class FakeLLMClient:
"""Duck-typed stand-in for `LLMClient` used in tests."""
def __init__(self, memories: list[GeneratedMemory] | Exception):
self._result = memories
def generate_structured(self, **kwargs):
if isinstance(self._result, Exception):
raise self._result
return self._result
def _make_character(session) -> str:
char = Character(
name="Test Character",
short_description="A test",
backstory="Born in a test. Lived in a test. Died in a test.",
aggression=6,
risk_tolerance=6,
patience=5,
trash_talk=4,
target_elo=1600,
adaptive=False,
opening_preferences=["Ruy Lopez", "Sicilian Najdorf"],
voice_descriptor="test voice",
quirks="never blinks",
state=CharacterState.GENERATING_MEMORIES,
)
session.add(char)
session.commit()
return char.id
def _fake_memories(n: int = 30) -> list[GeneratedMemory]:
out: list[GeneratedMemory] = []
types = list(MemoryType)
for i in range(n):
out.append(
GeneratedMemory(
scope=MemoryScope.CHARACTER_LORE,
type=types[i % len(types)],
emotional_valence=(i % 5 - 2) / 2.0, # spread -1..1
triggers=[f"trigger_{i}", f"alt_{i}"],
narrative_text=f"This is the {i}-th fake memory. It has enough length to pass validation.",
relevance_tags=[f"tag_{i % 3}"],
)
)
return out
def test_build_prompt_contains_character_details():
char = Character(
name="Vera",
short_description="quiet",
backstory="a long backstory here",
aggression=9,
risk_tolerance=2,
patience=3,
trash_talk=1,
target_elo=2000,
adaptive=True,
opening_preferences=["Ruy Lopez"],
voice_descriptor="calm",
quirks="hums",
)
prompt = build_prompt(char, target=40, minimum=30, maximum=50)
assert "Vera" in prompt
assert "a long backstory here" in prompt
assert "Ruy Lopez" in prompt
assert "2000" in prompt
assert "adapts" in prompt.lower() # adaptive line
def test_generate_and_store_persists_and_marks_ready():
with SessionLocal() as s:
character_id = _make_character(s)
fake = FakeLLMClient(_fake_memories(30))
count = generate_and_store(character_id, client=fake)
assert count == 30
with SessionLocal() as s:
char = s.get(Character, character_id)
assert char is not None
assert char.state == CharacterState.READY
assert char.memory_generation_error is None
memories = list(s.execute(select(Memory).where(Memory.character_id == character_id)).scalars())
assert len(memories) == 30
# Spread check — we should see multiple distinct types.
assert len({m.type for m in memories}) >= 4
def test_generate_and_store_failure_marks_character_failed():
with SessionLocal() as s:
character_id = _make_character(s)
fake = FakeLLMClient(RuntimeError("fake Gemini outage"))
import pytest
with pytest.raises(RuntimeError):
generate_and_store(character_id, client=fake)
with SessionLocal() as s:
char = s.get(Character, character_id)
assert char is not None
assert char.state == CharacterState.GENERATION_FAILED
assert char.memory_generation_error is not None
assert "fake Gemini outage" in char.memory_generation_error
def test_generate_and_store_rejects_too_few():
"""If the LLM returns a suspiciously tiny batch, we fail the character."""
with SessionLocal() as s:
character_id = _make_character(s)
fake = FakeLLMClient(_fake_memories(3)) # below min//2
import pytest
with pytest.raises(Exception):
generate_and_store(character_id, client=fake)
with SessionLocal() as s:
char = s.get(Character, character_id)
assert char.state == CharacterState.GENERATION_FAILED
|