Bhargav
Initial KinChat env: models, personas, scenarios, rubrics, grader, env loop, FastAPI app, client, dashboard, baseline inference (377 tests passing)
2e8387b | """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") | |
| 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 | |