kinchat / tests /test_models.py
Bhargav
Initial KinChat env: models, personas, scenarios, rubrics, grader, env loop, FastAPI app, client, dashboard, baseline inference (377 tests passing)
2e8387b
Raw
History Blame Contribute Delete
5.05 kB
"""TDD tests for kinchat.models β€” Pydantic schemas."""
import json
import pytest
from pydantic import ValidationError
from kinchat.models import (
ChatMsg,
KinChatAction,
KinChatObservation,
KinChatState,
PersonaState,
Secret,
)
# ---- KinChatAction ----
def test_action_valid_send():
a = KinChatAction(action_type="send", message="hi", recipients=["mom"])
assert a.action_type == "send"
assert a.recipients == ["mom"]
def test_action_stay_silent_defaults():
a = KinChatAction(action_type="stay_silent")
assert a.message == ""
assert a.recipients == []
assert a.reasoning == ""
def test_action_rejects_invalid_type():
with pytest.raises(ValidationError):
KinChatAction(action_type="shout")
@pytest.mark.parametrize("t", ["send", "edit", "block", "suggest", "stay_silent"])
def test_action_all_five_types(t):
KinChatAction(action_type=t)
def test_action_json_roundtrip():
a = KinChatAction(
action_type="edit",
message="softer phrasing",
recipients=["grandma"],
reasoning="avoid worry",
)
blob = a.model_dump_json()
b = KinChatAction.model_validate_json(blob)
assert b == a
# ---- ChatMsg ----
def test_chatmsg_basic():
m = ChatMsg(sender="mom", text="dinner?", recipients=["user"], turn=3)
assert m.turn == 3
assert m.recipients == ["user"]
def test_chatmsg_group_default_recipients():
m = ChatMsg(sender="sib1", text="hi all", turn=0)
assert m.recipients == [] # empty = group chat
# ---- PersonaState ----
def test_persona_state_defaults():
p = PersonaState(persona_id="mom")
assert 0.0 <= p.trust <= 1.0
assert p.mood in {"calm", "annoyed", "worried", "warm"}
assert isinstance(p.known_facts, set)
def test_persona_state_known_facts_serializes_as_list():
p = PersonaState(persona_id="dad", known_facts={"fact_1", "fact_2"})
blob = json.loads(p.model_dump_json())
assert isinstance(blob["known_facts"], list)
assert set(blob["known_facts"]) == {"fact_1", "fact_2"}
def test_persona_state_roundtrip_set_preserved():
p = PersonaState(persona_id="sib1", known_facts={"a", "b"})
p2 = PersonaState.model_validate_json(p.model_dump_json())
assert p2.known_facts == {"a", "b"}
def test_persona_invalid_mood_rejected():
with pytest.raises(ValidationError):
PersonaState(persona_id="x", mood="enraged")
def test_persona_trust_range_enforced():
with pytest.raises(ValidationError):
PersonaState(persona_id="x", trust=1.5)
with pytest.raises(ValidationError):
PersonaState(persona_id="x", trust=-0.1)
# ---- Secret ----
def test_secret_basic():
s = Secret(
fact_id="grandma_surgery",
text="grandma is having knee surgery",
owners=["mom", "dad"],
sensitivity=0.8,
)
assert s.sensitivity == 0.8
def test_secret_sensitivity_range():
with pytest.raises(ValidationError):
Secret(fact_id="x", text="y", owners=[], sensitivity=1.2)
# ---- KinChatState ----
def test_kinchat_state_construction():
st = KinChatState(
session_id="s1",
episode_index=0,
scenario_id="secret_grandma_01",
family={"mom": PersonaState(persona_id="mom")},
secrets=[Secret(fact_id="f", text="t", owners=["mom"], sensitivity=0.5)],
chat_log=[],
turn_index=0,
scores_history=[],
)
assert st.episode_index == 0
assert "mom" in st.family
def test_kinchat_state_roundtrip():
st = KinChatState(
session_id="s1",
episode_index=2,
scenario_id="sc",
family={"mom": PersonaState(persona_id="mom", known_facts={"f1"})},
secrets=[],
chat_log=[ChatMsg(sender="mom", text="hi", turn=0)],
turn_index=1,
scores_history=[{"leak": 0.0, "audience_fit": 0.7}],
)
st2 = KinChatState.model_validate_json(st.model_dump_json())
assert st2.family["mom"].known_facts == {"f1"}
assert st2.chat_log[0].text == "hi"
# ---- KinChatObservation ----
def test_observation_construction():
obs = KinChatObservation(
chat_history=[ChatMsg(sender="mom", text="hi", turn=0)],
user_draft="hey mom",
active_recipients=["mom"],
turn_index=0,
scenario_brief="mom asks how work is going",
reward=0.42,
reward_breakdown={"leak": 0.0, "audience_fit": 0.8, "restraint": 0.5, "trust_delta": 0.1},
feedback="ok",
done=False,
episode_id="ep_0",
)
assert obs.done is False
assert obs.reward == 0.42
assert obs.reward_breakdown["audience_fit"] == 0.8
def test_observation_roundtrip():
obs = KinChatObservation(
chat_history=[],
user_draft="",
active_recipients=[],
turn_index=0,
scenario_brief="",
reward=0.0,
reward_breakdown={},
feedback="",
done=True,
episode_id="ep_X",
)
obs2 = KinChatObservation.model_validate_json(obs.model_dump_json())
assert obs2 == obs