interactive-chat / tests /test_integration.py
Junhoee's picture
Upload 162 files
1c9c13f verified
Raw
History Blame Contribute Delete
4.02 kB
"""M4 전체 관톡 β€” 읽기 루프 β†’ κ°œμž… 포켓(μ±„νŒ…) β†’ 볡귀 β†’ μ—”λ”©κΉŒμ§€ ν•œ λ²ˆμ—."""
import json
import pytest
from engine.plugins.logging import TurnLoggingPlugin
from engine.repositories.content import ContentRepository
from engine.repositories.playlog import PlaylogRepository
from engine.services.pocket import PocketService
from engine.services.state import AXIS_DELTA
from engine.services.story import StoryEngine
from tests.fakes import ScriptedLlm, text_response, tool_call, tool_response
@pytest.fixture(scope="module")
def repo():
return ContentRepository("content")
@pytest.mark.asyncio
async def test_full_playthrough_with_pocket(repo, tmp_path):
"""E06-09κΉŒμ§€ 읽고 β†’ 포켓 μ±„νŒ… 2ν„΄(수렴) β†’ μƒνƒœ 컀밋 β†’ μ΄μ–΄μ„œ μ—”λ”© 도달."""
playlog = PlaylogRepository(tmp_path / "playlog.jsonl")
svc = PocketService(
repo,
plugins=[TurnLoggingPlugin(playlog)],
character_model=ScriptedLlm(script=[
text_response("β€¦κ·Έλž˜. λ„ˆμ™€ λ‚˜ μ‚¬μ΄μ˜ 일이야, 둜라."),
text_response("μ°©ν•˜μ§€. 우리끼리만 κ°„μ§ν•˜μž."),
text_response("β€¦μ΄μ œ 됐어. 아무 말도 ν•„μš” μ—†μ–΄."),
]),
director_model=ScriptedLlm(script=[
tool_response(tool_call("update_trust", direction="trust")),
text_response("계속"),
tool_response(tool_call("update_trust", direction="trust"),
tool_call("mark_beat", beat="λ‘˜λ§Œμ˜ λΉ„λ°€ 동쑰")),
text_response("계속"),
tool_response(tool_call("finish_pocket", reason="goal_reached")),
text_response("수렴"),
]),
)
# 1) 읽기 루프: E06-09κΉŒμ§€ μ‹ λ’° μ„±ν–₯으둜 μ§„ν–‰
engine = StoryEngine(repo)
step = engine.start()
while engine.current_id != "E06-09":
if step.choices:
idx = next((i for i, c in enumerate(step.choices) if c.axis == "trust"),
next((i for i, c in enumerate(step.choices)
if c.axis in (None, "neutral")), 0))
_, step = engine.choose(idx)
else:
step = engine.advance()
trust_before = engine.state.trust_score
# 2) κ°œμž… 포켓: μžμœ μ±„νŒ… 3ν„΄ β†’ director 수렴 (μ΅œμ†Œ 체λ₯˜ 3ν„΄)
sid = await svc.open("E06-09", engine.state)
t1 = await svc.run_turn(sid, "β€¦μš°λ¦¬ λ‘˜λ§Œμ˜ μΌμ΄λΌλŠ” κ±°μ§€?")
assert not t1.converged and "둜라" in t1.reply
t2 = await svc.run_turn(sid, "μ•Œμ•˜μ–΄. μ•„λ¬΄μ—κ²Œλ„ λ§ν•˜μ§€ μ•Šμ„κ²Œ.")
assert not t2.converged # μ΅œμ†Œ 체λ₯˜ ν„΄ 미달
t3 = await svc.run_turn(sid, "…응. μ•½μ†ν• κ²Œ.")
assert t3.converged and t3.reason == "goal_reached"
# 3) 볡귀: μˆ¨μ€ μƒνƒœ 컀밋 (μ±„νŒ… 2ν„΄ = trust +2Γ—AXIS_DELTA)
log = await svc.close(sid, engine.state)
assert engine.state.trust_score == trust_before + 2 * AXIS_DELTA
assert log.beats_hit == ["λ‘˜λ§Œμ˜ λΉ„λ°€ 동쑰"]
# 4) μ΄μ–΄μ„œ 읽기 β†’ μ—”λ”© (μ‹ λ’° μ„±ν–₯ μœ μ§€ β†’ μ˜μ›)
while step.ending is None:
if step.choices:
idx = next((i for i, c in enumerate(step.choices) if c.axis == "trust"),
next((i for i, c in enumerate(step.choices)
if c.axis in (None, "neutral")), 0))
_, step = engine.choose(idx)
else:
step = engine.advance()
assert step.ending.id == "ending_eternal"
assert "E06-10" in engine.visited # 도달점은 μ±„νŒ…κ³Ό λ¬΄κ΄€ν•˜κ²Œ 톡과
# 5) ν„΄ 둜그: μœ μ € μž…λ ₯/이벀트/ν„΄ μš”μ•½μ΄ 기둝됨 (연ꡬ 데이터)
records = [json.loads(l) for l in (tmp_path / "playlog.jsonl").read_text().splitlines()]
kinds = {r["kind"] for r in records}
assert {"user_input", "event", "turn_summary"} <= kinds
tool_events = [r for r in records if r.get("tool_calls")]
assert any(c["tool"] == "finish_pocket" for r in tool_events for c in r["tool_calls"])