157 lines
5.1 KiB
Python
157 lines
5.1 KiB
Python
"""大周天抽取候选审核服务测试(记忆候选 + 世界实体候选)。"""
|
|
|
|
import pytest
|
|
from sqlalchemy import select
|
|
|
|
from app.core.errors import AppError
|
|
from app.db.session import AsyncSessionLocal
|
|
from app.models.big_cycle import BigCycle
|
|
from app.models.candidates import MemoryCandidate
|
|
from app.models.memory import Memory
|
|
from app.models.world import CharacterWorldEntity
|
|
from app.services import extraction as extraction_service
|
|
from app.services.characters import get_active_character_model
|
|
|
|
|
|
async def _seed_cycle(session, character_id: str) -> str:
|
|
cycle = BigCycle(
|
|
character_id=character_id,
|
|
trigger="test",
|
|
status="completed",
|
|
memory_count_at_trigger=20,
|
|
)
|
|
session.add(cycle)
|
|
await session.flush()
|
|
return cycle.id
|
|
|
|
|
|
async def _seed_memory_candidate(
|
|
session, character_id: str, cycle_id: str, status: str = "pending"
|
|
) -> str:
|
|
cand = MemoryCandidate(
|
|
character_id=character_id,
|
|
cycle_id=cycle_id,
|
|
type="preference",
|
|
title="喜欢简洁",
|
|
content="用户偏好简洁直接的回答",
|
|
confidence=0.7,
|
|
importance=0.8,
|
|
sensitivity="low",
|
|
status=status,
|
|
)
|
|
session.add(cand)
|
|
await session.flush()
|
|
return cand.id
|
|
|
|
|
|
async def _seed_world_entity(session, character_id: str, status: str = "pending") -> str:
|
|
e = CharacterWorldEntity(
|
|
character_id=character_id,
|
|
type="project",
|
|
name="项目X",
|
|
state_type="inference",
|
|
confidence=0.6,
|
|
status=status,
|
|
)
|
|
session.add(e)
|
|
await session.flush()
|
|
return e.id
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_approve_memory_candidate_derives_memory() -> None:
|
|
async with AsyncSessionLocal() as session:
|
|
character = await get_active_character_model(session)
|
|
cycle_id = await _seed_cycle(session, character.id)
|
|
cid = await _seed_memory_candidate(session, character.id, cycle_id)
|
|
await session.commit()
|
|
|
|
resp = await extraction_service.approve_memory_proposal(cid)
|
|
assert resp.status == "applied"
|
|
|
|
async with AsyncSessionLocal() as session:
|
|
mem = (
|
|
await session.execute(
|
|
select(Memory).where(
|
|
Memory.character_id == character.id,
|
|
Memory.title == "喜欢简洁",
|
|
)
|
|
)
|
|
).scalar_one_or_none()
|
|
assert mem is not None
|
|
assert mem.source == "big_cycle"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_reject_memory_candidate() -> None:
|
|
async with AsyncSessionLocal() as session:
|
|
character = await get_active_character_model(session)
|
|
cycle_id = await _seed_cycle(session, character.id)
|
|
cid = await _seed_memory_candidate(session, character.id, cycle_id)
|
|
await session.commit()
|
|
|
|
resp = await extraction_service.reject_memory_proposal(cid)
|
|
assert resp.status == "rejected"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_approve_non_pending_memory_conflicts() -> None:
|
|
async with AsyncSessionLocal() as session:
|
|
character = await get_active_character_model(session)
|
|
cycle_id = await _seed_cycle(session, character.id)
|
|
cid = await _seed_memory_candidate(session, character.id, cycle_id, status="applied")
|
|
await session.commit()
|
|
|
|
with pytest.raises(AppError):
|
|
await extraction_service.approve_memory_proposal(cid)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_approve_world_entity_confirms() -> None:
|
|
async with AsyncSessionLocal() as session:
|
|
character = await get_active_character_model(session)
|
|
eid = await _seed_world_entity(session, character.id)
|
|
await session.commit()
|
|
|
|
resp = await extraction_service.approve_world_entity(eid)
|
|
assert resp.status == "confirmed"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_reject_world_entity() -> None:
|
|
async with AsyncSessionLocal() as session:
|
|
character = await get_active_character_model(session)
|
|
eid = await _seed_world_entity(session, character.id)
|
|
await session.commit()
|
|
|
|
resp = await extraction_service.reject_world_entity(eid)
|
|
assert resp.status == "rejected"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_list_memory_proposals_source_cycle() -> None:
|
|
async with AsyncSessionLocal() as session:
|
|
character = await get_active_character_model(session)
|
|
cycle_id = await _seed_cycle(session, character.id)
|
|
await _seed_memory_candidate(session, character.id, cycle_id)
|
|
# 导入来源候选(import_job_id 非空)
|
|
session.add(
|
|
MemoryCandidate(
|
|
character_id=character.id,
|
|
import_job_id="import_test",
|
|
type="user",
|
|
title="导入记忆",
|
|
content="来自导入",
|
|
confidence=0.5,
|
|
importance=0.5,
|
|
sensitivity="low",
|
|
status="pending",
|
|
)
|
|
)
|
|
await session.commit()
|
|
|
|
page = await extraction_service.list_memory_proposals(character_id=character.id, source="cycle")
|
|
assert page.total == 1
|
|
assert page.items[0].title == "喜欢简洁"
|
|
assert page.items[0].cycle_id == cycle_id
|