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()