themis / phase1 /eval /test_case_summary_chat.py
vg15o2's picture
Moonley backend (HF Space build)
1d9bd9b
Raw
History Blame Contribute Delete
5.49 kB
import json
import os
import sys
import tempfile
import unittest
HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, os.path.join(HERE, "..", "scripts"))
from agent import case_chat_answer, case_chat_grounded_response
from case_summary import case_summary_record, load_case_summaries
class CaseSummaryTest(unittest.TestCase):
def test_extracted_summary_has_priority(self):
result = case_summary_record(
{"held": "Reporter holding"},
{"held": "Synthetic holding", "model": "model-a"},
{"summary": "Extraction summary", "provider": "indian_kanoon", "version": "v1"},
)
self.assertEqual(result["text"], "Extraction summary")
self.assertEqual(result["source"], "extracted_summary")
self.assertEqual(result["provider"], "indian_kanoon")
def test_reporter_and_synthetic_fallbacks_are_disclosed(self):
synthetic = case_summary_record({}, {"held": "Generated holding", "model": "model-a"}, {})
reporter = case_summary_record({"held": "Official reporter holding"}, {}, {})
self.assertTrue(synthetic["generated"])
self.assertEqual(synthetic["source"], "synthetic_headnote")
self.assertFalse(reporter["generated"])
self.assertEqual(reporter["source"], "reporter_headnote")
def test_opening_text_is_not_mislabeled_as_summary(self):
result = case_summary_record({"case_name": "No headnote"}, {}, {})
self.assertFalse(result["available"])
self.assertEqual(result["source"], "unavailable")
def test_loads_future_summary_sidecar(self):
with tempfile.TemporaryDirectory() as folder:
path = os.path.join(folder, "judgment_summaries.jsonl")
with open(path, "w", encoding="utf-8") as fh:
fh.write(json.dumps({"doc_id": "X", "summary": {"holding": "Appeal allowed."}}) + "\n")
rows, filename = load_case_summaries(folder)
self.assertEqual(filename, "judgment_summaries.jsonl")
self.assertIn("X", rows)
class CaseChatTest(unittest.TestCase):
def test_chat_prompt_contains_summary_but_no_full_text(self):
captured = {}
def llm(messages):
captured["messages"] = messages
return "The appeal was allowed."
answer = case_chat_answer(
"The Court allowed the appeal because notice was not served.",
"What was the outcome?",
[{"role": "assistant", "content": "Earlier answer"}],
"A v B",
"2024 INSC 1",
llm,
)
prompt = "\n".join(m["content"] for m in captured["messages"])
self.assertEqual(answer, "The appeal was allowed.")
self.assertIn("CASE SUMMARY", prompt)
self.assertIn("notice was not served", prompt)
self.assertNotIn("FULL JUDGMENT", prompt)
def test_chat_refuses_missing_summary(self):
called = []
answer = case_chat_answer("", "What was held?", [], "A v B", "", lambda m: called.append(m))
self.assertEqual(answer, "")
self.assertEqual(called, [])
def test_grounded_chat_resolves_only_server_held_evidence_ids(self):
captured = {}
passages = [
{"paragraph_id": "100:para:12", "label": "Paragraph 12", "text": "The appeal was allowed."},
{"paragraph_id": "100:para:18", "label": "Paragraph 18", "text": "The decree was set aside."},
]
def llm(messages):
captured["messages"] = messages
return json.dumps({"answer": "The decree was set aside.", "evidence_ids": ["E2", "E2"]})
result = case_chat_grounded_response(
"The Court decided the appeal.", passages, "What was the result?", [], "A v B", "2024 INSC 1", llm
)
prompt = "\n".join(m["content"] for m in captured["messages"])
self.assertTrue(result["supported"])
self.assertEqual([e["paragraph_id"] for e in result["evidence"]], ["100:para:18"])
self.assertIn("[E1] The appeal was allowed.", prompt)
self.assertIn("[E2] The decree was set aside.", prompt)
def test_grounded_chat_rejects_unknown_or_missing_evidence(self):
passages = [{"paragraph_id": "100:para:12", "text": "The appeal was allowed."}]
result = case_chat_grounded_response(
"Summary", passages, "Outcome?", [], "A v B", "", lambda _m: '{"answer":"Allowed", "evidence_ids":["E99"]}'
)
self.assertFalse(result["supported"])
self.assertEqual(result["evidence"], [])
self.assertIn("do not answer", result["answer"])
def test_grounded_chat_can_answer_from_passages_when_summary_is_missing(self):
passages = [{"paragraph_id": "100:para:12", "text": "The appeal was allowed."}]
result = case_chat_grounded_response(
"", passages, "What was the outcome?", [], "A v B", "", lambda _m: '{"answer":"The appeal was allowed.", "evidence_ids":["E1"]}'
)
self.assertTrue(result["supported"])
self.assertEqual(result["evidence"][0]["paragraph_id"], "100:para:12")
def test_grounded_chat_does_not_call_model_without_stored_passages(self):
called = []
result = case_chat_grounded_response(
"Summary", [], "Outcome?", [], "A v B", "", lambda messages: called.append(messages)
)
self.assertFalse(result["supported"])
self.assertEqual(called, [])
if __name__ == "__main__":
unittest.main()