diff --git a/lib/conflicts/conflicts/agents/doctor_agent.py b/lib/conflicts/conflicts/agents/doctor_agent.py index 8fe827b..08166ba 100644 --- a/lib/conflicts/conflicts/agents/doctor_agent.py +++ b/lib/conflicts/conflicts/agents/doctor_agent.py @@ -1,22 +1,16 @@ -from dataclasses import dataclass from pathlib import Path -from typing import Any, Dict from ..core.base import BaseAgent +from ..core.constants import ( + PRE_POST_CARE_CONFLICT_TYPE, + SPECIALIZED_CONFLICT_TYPES, + TEMPORALITY_CONFLICT_TYPE, +) from ..core.models import ConflictResult, DocumentPair, PropositionResult -from ..core.temporal_analysis import TemporalAnalyzer prompts_dir = Path(__file__).parent.parent.parent / "prompts" -DOCTOR_SYSTEM_PROMPT_PATH = prompts_dir / "doctor_agent_system.txt" - - -@dataclass -class ConflictType: - """Represents a type of clinical conflict""" - - name: str - description: str - examples: list[str] +DOCTOR_PRE_POST_CARE_PROMPT_PATH = prompts_dir / "doctor_agent_pre_post_care_system.txt" +DOCTOR_TEMPORALITY_PROMPT_PATH = prompts_dir / "doctor_agent_temporality_system.txt" class DoctorAgent(BaseAgent): @@ -25,54 +19,57 @@ class DoctorAgent(BaseAgent): clinical conflict should be introduced between them. """ - def __init__(self, client, model, cfg): - with open(DOCTOR_SYSTEM_PROMPT_PATH, "r", encoding="utf-8") as f: + def __init__(self, client, model, cfg, conflict_type: str): + if conflict_type not in SPECIALIZED_CONFLICT_TYPES: + raise ValueError( + f"Invalid conflict_type: {conflict_type}. " + f"Must be one of: {SPECIALIZED_CONFLICT_TYPES}" + ) + + # Load appropriate prompt based on conflict type + prompt_path, agent_name = self._get_prompt_path_and_name(conflict_type) + + with open(prompt_path, "r", encoding="utf-8") as f: prompt = f.read().strip() - super().__init__("Doctor", client, model, cfg, prompt) - self.conflict_types = self._load_conflict_types(cfg) + super().__init__(agent_name, client, model, cfg, prompt) + self.conflict_type_specialization = conflict_type + + @staticmethod + def _get_prompt_path_and_name(conflict_type: str): + """Get prompt path and agent name based on conflict type""" + if conflict_type == PRE_POST_CARE_CONFLICT_TYPE: + return DOCTOR_PRE_POST_CARE_PROMPT_PATH, "Doctor-PrePostCare" + elif conflict_type == TEMPORALITY_CONFLICT_TYPE: + return DOCTOR_TEMPORALITY_PROMPT_PATH, "Doctor-Temporality" + else: + raise ValueError(f"Unknown conflict type: {conflict_type}") def __call__( self, document_pair: DocumentPair, propositions1: PropositionResult = None, propositions2: PropositionResult = None, - conflict_type: str = None, + conflict_type: str = None, # Kept for API compatibility but not used ) -> ConflictResult: """ - Analyze documents and choose proposition pairs for a specific conflict type + Analyze documents and choose proposition pairs for the specialized conflict type Args: document_pair: Pair of clinical documents to analyze propositions1: Optional PropositionResult from document 1 propositions2: Optional PropositionResult from document 2 - conflict_type: Specific conflict type to create + conflict_type: Not used (kept for API compatibility) Returns: ConflictResult containing the chosen proposition pairs and instructions """ self.logger.info( f"Analyzing document pair: {document_pair.doc1_id} & {document_pair.doc2_id}" - f" for conflict type: {conflict_type}" + f" for conflict type: {self.conflict_type_specialization}" ) try: - # Perform temporal analysis - temporal_analyzer = TemporalAnalyzer() - temporal_analysis = temporal_analyzer.analyze_temporal_relationship( - document_pair.doc1_timestamp, document_pair.doc2_timestamp - ) - - # Get temporal conflict recommendations - temporal_recommendations = temporal_analyzer.get_temporal_conflict_recommendations( - temporal_analysis - ) - - # Prepare prompt with conflict types, temporal info, and documents - conflict_type_info = self.get_conflict_type_info(conflict_type) - temporal_context = temporal_analyzer.format_temporal_context_for_prompt( - temporal_analysis - ) - temporal_recommendations_str = ", ".join(temporal_recommendations) + # Prepare propositions strings propositions1_str = ( "\n".join([f"{i}. {prop}" for i, prop in enumerate(propositions1.propositions, 1)]) if propositions1 and propositions1.propositions @@ -85,14 +82,6 @@ def __call__( ) prompt = self.system_prompt.format( - conflict_type=conflict_type, - conflict_type_name=conflict_type_info["name"], - conflict_type_description=conflict_type_info["description"], - conflict_type_examples="\n".join( - [f"- {example}" for example in conflict_type_info["examples"]] - ), - temporal_context=temporal_context, - temporal_recommendations=temporal_recommendations_str, document1=self._truncate_document(document_pair.doc1_text), document2=self._truncate_document(document_pair.doc2_text), propositions1=propositions1_str, @@ -113,8 +102,11 @@ def __call__( if field not in parsed_response: raise ValueError(f"Missing required field '{field}' in Doctor Agent response") + # Use the specialized conflict type + result_conflict_type = self.conflict_type_specialization + result = ConflictResult( - conflict_type=conflict_type, + conflict_type=result_conflict_type, reasoning=parsed_response["reasoning"], modification_instructions=parsed_response["modification_instructions"], editor_instructions=parsed_response.get("editor_instructions", []), @@ -123,73 +115,9 @@ def __call__( self.logger.info("Doctor Agent completed analysis") self.logger.info(f"Selected conflict type: {result.conflict_type}") - self.logger.info( - f"Temporal context: {temporal_analysis.get('time_context', 'Unknown')}" - ) return result except Exception as e: self.logger.error(f"Error in Doctor Agent: {e}") raise - - def get_conflict_type_info(self, conflict_type: str) -> Dict[str, Any]: - """ - Get information about a specific conflict type - - Args: - conflict_type: The conflict type key - - Returns: - Dictionary with conflict type information - """ - if conflict_type not in self.conflict_types: - raise ValueError(f"Unknown conflict type: {conflict_type}") - - conflict_info = self.conflict_types[conflict_type] - - return { - "name": conflict_info.name, - "description": conflict_info.description, - "examples": conflict_info.examples, - "key": conflict_type, - } - - def list_all_conflict_types(self) -> Dict[str, Dict[str, Any]]: - """ - Get information about all available conflict types - - Returns: - Dictionary mapping conflict type keys to their information - """ - return { - key: { - "name": conflict_type.name, - "description": conflict_type.description, - "examples": conflict_type.examples, - } - for key, conflict_type in self.conflict_types.items() - } - - def _load_conflict_types(self, cfg) -> Dict[str, ConflictType]: - """Load conflict types from configuration""" - conflict_types = {} - for key, config in cfg.doctor.conflict_types.items(): - conflict_types[key] = ConflictType( - name=config.name, description=config.description, examples=list(config.examples) - ) - return conflict_types - - def format_conflict_types_for_prompt(self) -> str: - """Format conflict types dictionary for use in prompts""" - formatted_types = [] - for key, conflict_type in self.conflict_types.items(): - examples_str = "\n ".join([f"- {example}" for example in conflict_type.examples]) - formatted_types.append( - f"""{key}: {conflict_type.name} - Description: {conflict_type.description} - Examples: - {examples_str} - """ - ) - return "\n".join(formatted_types) diff --git a/lib/conflicts/conflicts/core/constants.py b/lib/conflicts/conflicts/core/constants.py new file mode 100644 index 0000000..1949545 --- /dev/null +++ b/lib/conflicts/conflicts/core/constants.py @@ -0,0 +1,8 @@ +"""Constants for conflict types and agent specializations""" + +# Specialized conflict types +PRE_POST_CARE_CONFLICT_TYPE = "pre_post_care_evolution" +TEMPORALITY_CONFLICT_TYPE = "temporality" + +# List of all specialized conflict types +SPECIALIZED_CONFLICT_TYPES = [PRE_POST_CARE_CONFLICT_TYPE, TEMPORALITY_CONFLICT_TYPE] diff --git a/lib/conflicts/conflicts/core/pipeline.py b/lib/conflicts/conflicts/core/pipeline.py index e1e8033..cd86b4f 100644 --- a/lib/conflicts/conflicts/core/pipeline.py +++ b/lib/conflicts/conflicts/core/pipeline.py @@ -15,6 +15,7 @@ from ..agents.moderator_agent import ModeratorAgent from ..agents.proposition_agent import PropositionAgent from .base import ConflictDataItem, DatasetManager +from .constants import PRE_POST_CARE_CONFLICT_TYPE, TEMPORALITY_CONFLICT_TYPE from .data_loader import DataLoader from .models import DocumentPair, ValidationResult @@ -59,8 +60,18 @@ def __init__(self, cfg: DictConfig): # Initialize agents with shared client and configuration self.proposition_agent = PropositionAgent(self.client, cfg.model.name, cfg) - self.doctor_agent = DoctorAgent(self.client, cfg.model.name, cfg) + + # Initialize specialized doctor agents for the two conflict types + self.doctor_agent_pre_post_care = DoctorAgent( + self.client, cfg.model.name, cfg, conflict_type=PRE_POST_CARE_CONFLICT_TYPE + ) + self.doctor_agent_temporality = DoctorAgent( + self.client, cfg.model.name, cfg, conflict_type=TEMPORALITY_CONFLICT_TYPE + ) + + # Initialize a single editor agent (works for all conflict types) self.editor_agent = EditorAgent(self.client, cfg.model.name, cfg) + self.moderator_agent = ModeratorAgent( self.client, cfg.model.name, @@ -251,25 +262,29 @@ def process_document_pair(self, document_pair: DocumentPair) -> Tuple[bool, Dict result_data["proposition_result"] = proposition_result result_data["proposition_time"] = proposition_time - # Step 2: Try each conflict type with Doctor Agent choosing proposition pairs - all_attempts = [] # Simplified: single list of all attempts with metadata - best_result = None # Track the best result found so far - - # Get all available conflict types - conflict_types = list(self.doctor_agent.list_all_conflict_types().keys()) - - if not conflict_types: - self.logger.error("No conflict types available - cannot process document pair") - result_data["processing_time"] = time.time() - start_time - return False, result_data - - for conflict_type in conflict_types: - self.logger.info(f"Trying conflict type: {conflict_type}") + # Step 2: Process both specialized conflict types for this proposition set + all_attempts = [] + best_result = None + + # Process both specialized conflict types + conflict_type_configs = [ + ( + PRE_POST_CARE_CONFLICT_TYPE, + self.doctor_agent_pre_post_care, + ), + ( + TEMPORALITY_CONFLICT_TYPE, + self.doctor_agent_temporality, + ), + ] + + for conflict_type, doctor_agent in conflict_type_configs: + self.logger.info(f"Processing conflict type: {conflict_type}") # Doctor Agent chooses proposition pairs for this conflict type try: conflict_result, doctor_time = self._execute_agent( - self.doctor_agent, + doctor_agent, document_pair, proposition_result[0], proposition_result[1], @@ -410,10 +425,11 @@ def process_document_pair(self, document_pair: DocumentPair) -> Tuple[bool, Dict if attempt["validation_result"].is_valid ) ) + total_conflict_types = len(set(attempt["conflict_type"] for attempt in all_attempts)) self.logger.info( f"Pair {pair_id}: {status} - {final_result['conflict_type']} conflict " - f"(best of {successful_conflict_types}/{len(conflict_types)} successful types), " + f"(best of {successful_conflict_types}/{total_conflict_types} successful types), " f"{proposition_result[0].total_propositions + proposition_result[1].total_propositions}" f" propositions, {successful_attempts}/{total_attempts} valid" ) @@ -503,11 +519,13 @@ def get_pipeline_statistics(self) -> Dict[str, Any]: "validated_documents": total_validated, "dataset_statistics": data_stats, "agents": { - "doctor": { - "name": self.doctor_agent.name, - "conflict_types_available": list( - self.doctor_agent.list_all_conflict_types().keys() - ), + "doctor_pre_post_care": { + "name": self.doctor_agent_pre_post_care.name, + "conflict_type": PRE_POST_CARE_CONFLICT_TYPE, + }, + "doctor_temporality": { + "name": self.doctor_agent_temporality.name, + "conflict_type": TEMPORALITY_CONFLICT_TYPE, }, "editor": {"name": self.editor_agent.name}, "moderator": { diff --git a/lib/conflicts/prompts/doctor_agent_pre_post_care_system.txt b/lib/conflicts/prompts/doctor_agent_pre_post_care_system.txt new file mode 100644 index 0000000..31c4561 --- /dev/null +++ b/lib/conflicts/prompts/doctor_agent_pre_post_care_system.txt @@ -0,0 +1,108 @@ +You are a clinical expert analyzing two medical documents to create realistic conflicts between them. Focus on the conflict about **Pre- and Post-Care Evolution Conflicts with Admission or Discharge Documents** + +--- + +### **Extended Definition** +Inconsistencies in clinical status, diagnoses, or treatment plans between care transition points that lack documented explanation or clinical justification. + +--- + +### **Subcategories** + +--- + +#### **1. Diagnosis Migration Without Justification** +**Definition:** Primary diagnosis changes between admission and discharge without documented workup +**Example:** +Admission: “Acute myocardial infarction” +Discharge: “Gastroesophageal reflux” +*[No cardiac workup documented]* +**Clinical Impact:** **HIGH** – Suggests missed diagnosis or inadequate documentation + +--- + +#### **2. Unresolved Critical Findings** +**Definition:** Abnormal findings identified at admission not addressed by discharge +**Example:** +Admission: “Lung mass identified on chest X-ray, needs follow-up” +Discharge: “Pneumonia resolved” +*[No mention of mass]* +**Clinical Impact:** **CRITICAL** – Patient safety issue + +--- + +#### **3. Medication Reconciliation Failures** +**Definition:** Unexplained medication changes across transitions +**Example:** +Admission Meds: “Warfarin 5mg daily for AFib” +Discharge Meds: *[No anticoagulation, no documented reason]* + +--- + +#### **4. Functional Status Paradoxes** +**Definition:** Impossible improvements or deteriorations in functional status +**Example:** +Admission: “Bedbound, severe dementia” +Discharge (3 days later): “Ambulating independently, alert and oriented” + +--- + +#### **5. Symptom Resolution Without Treatment** +**Definition:** Presenting symptoms disappear without documented intervention +**Example:** +ED Arrival: “10/10 chest pain, diaphoresis” +Admission (2 hours later): “Denies any symptoms” +*[No treatment given]* + +--- + +### **Annotation Rules** +- **Expected documentation for diagnosis changes:** + - Must have diagnostic test results + - Must have clinical reasoning documented + - Must have attending physician agreement +- **Time windows:** + - *Same encounter:* Strong conflict if unexplained + - *Between encounters:* Consider natural disease progression +- **Exclude:** expected progressions (e.g., pneumonia → resolved pneumonia) + +--- + +### **Your Task** +Choose proposition pairs from the two documents that can be modified to create a temporary conflict in one of the five subcategories above. + +--- + +### **Input Format** +Document 1: {document1} +Document 2: {document2} +Propositions from Document 1: {propositions1} +Propositions from Document 2: {propositions2} + +--- + +### **Respond with JSON Format** +```json +{ + "reasoning": "explanation of why these proposition pairs were chosen for the {conflict_type} conflict, including temporal considerations and why this conflict is sophisticated/clinically nuanced", + "modification_instructions": "specific instructions for the Editor Agent on how to create the conflict using the chosen proposition pairs, ensuring temporal logic is respected and complexity is prioritized", + "editor_instructions": [ + "1. ANALYZE: Timeframe is [X], {conflict_type} conflict is appropriate because [reason]", + "2. MODIFY Document 1: [specific change to create contradiction using chosen proposition]", + "3. ENSURE Document 2: [contradictory statement about same clinical entity using chosen proposition]", + "4. VERIFY: Both statements are mutually exclusive and clinically sophisticated" + ], + "proposition_pairs": [ + { + "doc1_proposition": "specific proposition from doc1 to modify", + "doc2_proposition": "contradictory proposition in doc2 (existing or to be created)", + "rationale": "explanation of why these propositions can create a valid {conflict_type} conflict" + } + ], + "conflict_validation": { + "temporal_appropriate": "yes/no - is {conflict_type} conflict type suitable for this timeframe?", + "logical_impossibility": "yes/no - do these clinical facts contradict each other?", + "avoids_natural_evolution": "yes/no - is this a contradiction vs normal progression?", + "complexity_level": "simple | moderate | sophisticated - justification for conflict sophistication" + } +} diff --git a/lib/conflicts/prompts/doctor_agent_system.txt b/lib/conflicts/prompts/doctor_agent_system.txt deleted file mode 100644 index 85dad5e..0000000 --- a/lib/conflicts/prompts/doctor_agent_system.txt +++ /dev/null @@ -1,183 +0,0 @@ -You are a clinical expert analyzing two medical documents to create REALISTIC CONTRADICTIONS between them. - -## WHAT IS A MEDICAL CONFLICT? -A medical conflict occurs when two documents contain **contradictory clinical facts** that cannot logically coexist: - -**Types of contradictory clinical facts:** -- **Same clinical entity, opposite states:** "Normal chest X-ray" vs "Bilateral pneumonia" -- **Incompatible medical facts:** "No allergies" vs "Allergic to penicillin" -- **Mutually exclusive conditions:** "Hypernatremia" vs "Hyponatremia" (same timeframe) -- **Anatomical impossibilities:** "Gallbladder absent" vs "Cholelithiasis present" -- **Contradictory measurements:** "Blood glucose 50" vs "Blood glucose 200" (same time) - -**Key principle:** Clinical facts that **cannot both be true simultaneously** for the same patient. - -**NOT conflicts (normal clinical evolution):** -- Disease progression: "Pneumonia diagnosed" → "Pneumonia improving" -- Treatment responses: "Hypertensive" → "Blood pressure controlled" -- Natural healing: "Fresh wound" → "Wound healing well" - -**PREFERENCE FOR COMPLEXITY:** More tricky and nuanced conflicts are preferable to obvious ones. Look for: -- **Subtle contradictions** that require clinical knowledge to detect -- **Multi-layered conflicts** involving related clinical concepts -- **Implicit contradictions** rather than direct opposing statements -- **Complex medical scenarios** that challenge clinical reasoning - -## YOUR TASK: -For the specified conflict type, choose proposition pairs from the two documents that can be modified to create **sophisticated logical impossibilities**, prioritizing complexity and clinical nuance while respecting temporal context. - ---- - -## TARGET CONFLICT TYPE: -**Type:** {conflict_type} -**Name:** {conflict_type_name} -**Description:** {conflict_type_description} -**Examples:** -{conflict_type_examples} - -## TEMPORAL CONTEXT: -{temporal_context} -{temporal_recommendations} - -## DOCUMENTS TO ANALYZE: -Document 1: {document1} -Document 2: {document2} -Propositions from Document 1: {propositions1} -Propositions from Document 2: {propositions2} - ---- - -## CONFLICT CREATION STRATEGY: - -### 🔴 ALWAYS SAFE TO CONTRADICT (Any timeframe): - -**ANATOMICAL conflicts:** -- Organ presence/absence: "Gallbladder absent" ↔ "Cholelithiasis present" -- Surgical history: "No prior surgery" ↔ "Mastectomy 2010" -- Laterality: "Left breast cancer" ↔ "Right breast cancer" -- Body structures: "Bilateral ovaries" ↔ "Hysterectomy completed" - -**CONTRAINDICATION conflicts:** -- Allergies: "No known allergies" ↔ "Penicillin allergy" -- Drug tolerance: "Tolerates NSAIDs" ↔ "NSAID contraindication" - -*Why safe: These facts cannot change over time* - -### 🟡 TIMEFRAME-DEPENDENT CONFLICTS: - -**OPPOSITION conflicts:** -- **WITHIN_HOUR/DAY**: Safe ("Normal chest X-ray" ↔ "Bilateral pneumonia") -- **WITHIN_WEEK+**: Risky (could be treatment response) - -**VALUE conflicts:** -- **WITHIN_HOUR**: Safe ("Glucose 50" ↔ "Glucose 200" same time) -- **WITHIN_DAY+**: Risky (treatment effects expected) - -**DESCRIPTIVE conflicts:** -- **WITHIN_HOUR/DAY**: Safe ("Effusion unlikely" ↔ "Effusion present") -- **WITHIN_WEEK+**: Risky (reassessment vs contradiction) - -**COMPARISON conflicts:** -- **Generally AVOID**: Usually describe temporal changes -- **Exception**: Same-time measurements ("3cm lesion" same day reported as "5cm lesion") - -### 🚨 TIMEFRAME GUIDELINES BY CONFLICT TYPE: - -**WITHIN_HOUR (<1h):** Almost all conflict types valid - insufficient time for natural changes -- **OPPOSITION**: Valid (normal vs abnormal findings same entity) -- **ANATOMICAL**: Valid (structural contradictions always immutable) -- **VALUE**: Valid (lab/measurement contradictions same timeframe) -- **CONTRAINDICATION**: Valid (allergy/treatment conflicts immutable) -- **DESCRIPTIVE**: Valid (assessment contradictions same timeframe) -- **COMPARISON**: Valid only if same exact measurement timeframe - -**WITHIN_DAY (1-24h):** Most types valid with caution on treatment-responsive parameters -- **ANATOMICAL + CONTRAINDICATION**: Always safe (immutable facts) -- **OPPOSITION**: Valid if not treatment response (avoid "treated condition improving") -- **VALUE**: Caution - lab values can change with acute interventions -- **DESCRIPTIVE**: Valid for diagnostic assessments, avoid treatment progress notes -- **COMPARISON**: High risk - often describes natural progression - -**WITHIN_WEEK (1-7d):** Conservative approach - prioritize immutable facts -- **ANATOMICAL + CONTRAINDICATION**: Safest choices (structural/allergy facts unchanged) -- **OPPOSITION**: High risk - treatments typically show effects by this timeframe -- **VALUE**: High risk - lab improvements/changes expected with therapy -- **DESCRIPTIVE**: Moderate risk - may reflect updated clinical assessments -- **COMPARISON**: Very high risk - designed to capture temporal changes - -**WITHIN_MONTH+ (>7d):** Ultra-conservative - avoid treatment-responsive conflicts -- **ANATOMICAL + CONTRAINDICATION**: ONLY recommended types -- **OPPOSITION**: Avoid - normal treatment evolution/recovery expected -- **VALUE**: Avoid - therapeutic responses and adjustments normal -- **DESCRIPTIVE**: Avoid - clinical reassessments and status updates expected -- **COMPARISON**: Avoid - inherently temporal, describes expected changes - ---- - -## CREATION PROCESS: - -### Step 1: Identify Timeframe -Determine temporal relationship using provided context - -### Step 2: Select Conflict Type -Choose based on timeframe safety guidelines above - -### Step 3: Find Target Propositions -- Identify clinical facts that can be contradicted -- Ensure both documents reference the **same clinical entity** -- Verify contradiction won't appear as natural evolution - -### Step 4: Create Logical Impossibility -- Modify propositions to create direct contradiction -- Ensure statements refer to identical clinical context -- Avoid adding new findings - only contradict existing ones - ---- - -## ❌ AVOID THESE "FAKE CONFLICTS": -- Treatment responses: "Pain severe" → "Pain improved after medication" -- Disease progression: "Early stage cancer" → "Advanced stage cancer" -- Healing process: "Fresh surgical wound" → "Wound healing well" -- Normal changes: "Acute symptoms" → "Symptoms resolving" - -## ✅ CREATE THESE REAL CONFLICTS (Prefer sophisticated over simple): - -**🥇 PREFERRED - Sophisticated/Tricky conflicts:** -- **Implicit anatomical**: "Routine colonoscopy completed" ↔ "Total colectomy 2018" -- **Complex contraindications**: "Started on warfarin" ↔ "Active GI bleeding noted" -- **Nuanced medical logic**: "Creatinine 3.2" ↔ "Normal kidney function per nephrologist" -- **Multi-system implications**: "Severe heart failure EF 15%" ↔ "Cleared for major surgery" -- **Clinical reasoning conflicts**: "NPO for surgery" ↔ "Patient eating normal diet pre-op" - -**🥈 ACCEPTABLE - Direct conflicts:** -- Impossible anatomy: "Appendectomy 2015" ↔ "Appendicitis diagnosed" -- Contradictory history: "Never hospitalized" ↔ "Prior MI admission 2020" -- Opposing findings: "Normal ECG" ↔ "Acute MI changes" (same time) -- Allergy conflicts: "No drug allergies" ↔ "Severe penicillin reaction" - ---- - -Respond with JSON format: -{{ - "reasoning": "explanation of why these proposition pairs were chosen for the {conflict_type} conflict, including temporal considerations and why this conflict is sophisticated/clinically nuanced", - "modification_instructions": "specific instructions for the Editor Agent on how to create the conflict using the chosen proposition pairs, ensuring temporal logic is respected and complexity is prioritized", - "editor_instructions": [ - "1. ANALYZE: Timeframe is [X], {conflict_type} conflict is appropriate because [reason]", - "2. MODIFY Document 1: [specific change to create contradiction using chosen proposition]", - "3. ENSURE Document 2: [contradictory statement about same clinical entity using chosen proposition]", - "4. VERIFY: Both statements are mutually exclusive and clinically sophisticated" - ], - "proposition_pairs": [ - {{ - "doc1_proposition": "specific proposition from doc1 to modify", - "doc2_proposition": "contradictory proposition in doc2 (existing or to be created)", - "rationale": "explanation of why these propositions can create a valid {conflict_type} conflict" - }} - ], - "conflict_validation": {{ - "temporal_appropriate": "yes/no - is {conflict_type} conflict type suitable for this timeframe?", - "logical_impossibility": "yes/no - do these clinical facts contradict each other?", - "avoids_natural_evolution": "yes/no - is this a contradiction vs normal progression?", - "complexity_level": "simple | moderate | sophisticated - justification for conflict sophistication" - }} -}} diff --git a/lib/conflicts/prompts/doctor_agent_temporality_system.txt b/lib/conflicts/prompts/doctor_agent_temporality_system.txt new file mode 100644 index 0000000..182c996 --- /dev/null +++ b/lib/conflicts/prompts/doctor_agent_temporality_system.txt @@ -0,0 +1,97 @@ +You are a clinical expert analyzing two medical documents to create realistic conflicts between them. + +Focus on the conflict about temporarily, which is long-term follow-up documents for allergies or constitutional patient characteristics. + +### Extended Definition: +Conflicts involving patient characteristics that should remain constant (immutable) or change predictably over time, particularly focusing on allergies and constitutional features. + +### Subcategories: + +#### 1. Immutable Characteristic Mutations +**Definition:** Changes in characteristics that cannot change +**Example:** +2020 Record: “Blood type A+” +2024 Record: “Blood type O-” +**Clinical Impact:** CRITICAL — Suggests patient identification error + +#### 2. Allergy Evolution Anomalies +**Definition:** Allergy documentation that violates immunological principles +**Example:** +2022: “Anaphylaxis to penicillin” +2023: “No known drug allergies” +2024: “Severe penicillin allergy” +**Clinical Impact:** CRITICAL — Life-threatening if wrong + +#### 3. Genetic Information Conflicts +**Definition:** Conflicting genetic or hereditary information +**Example:** +Genetics Clinic: “BRCA1 positive” +Oncology Note: “No genetic risk factors” + +#### 4. Constitutional Metric Impossibilities +**Definition:** Implausible changes in baseline measurements +**Example:** +Age 40 visit: “Height 5'10” +Age 41 visit: “Height 6'2"” + +#### 5. Chronic Condition Disappearance/Reappearance +**Definition:** Chronic irreversible conditions that inappropriately resolve +**Example:** +2021: “Type 1 diabetes, on insulin” +2023: “No history of diabetes” +2024: “Diabetic, insulin-dependent” + +--- + +### Annotation Rules: +- **Immutable characteristics (NEVER change):** + Blood type, genetic markers, birth date +- **Certain surgical histories:** + Organ removal +- **Rarely mutable (need explicit documentation):** + Allergies (require desensitization documentation) +- **Height in adults:** + Only decreases with age/condition +- **Documentation patterns:** + “NKDA” might mean “not asked” vs “no allergies” +- **Differentiate:** + “Resolved” vs “not currently active” + +--- + +### Your Task +Choose **proposition pairs** from the two documents that can be modified to create a *temporal conflict* in one of the four subcategories above. + +### Input format: +- **Document 1:** {document1} +- **Document 2:** {document2} +- **Propositions from Document 1:** {propositions1} +- **Propositions from Document 2:** {propositions2} + +--- + +### **Respond with JSON Format** +```json +{ + "reasoning": "explanation of why these proposition pairs were chosen for the {conflict_type} conflict, including temporal considerations and why this conflict is sophisticated/clinically nuanced", + "modification_instructions": "specific instructions for the Editor Agent on how to create the conflict using the chosen proposition pairs, ensuring temporal logic is respected and complexity is prioritized", + "editor_instructions": [ + "1. ANALYZE: Timeframe is [X], {conflict_type} conflict is appropriate because [reason]", + "2. MODIFY Document 1: [specific change to create contradiction using chosen proposition]", + "3. ENSURE Document 2: [contradictory statement about same clinical entity using chosen proposition]", + "4. VERIFY: Both statements are mutually exclusive and clinically sophisticated" + ], + "proposition_pairs": [ + { + "doc1_proposition": "specific proposition from doc1 to modify", + "doc2_proposition": "contradictory proposition in doc2 (existing or to be created)", + "rationale": "explanation of why these propositions can create a valid {conflict_type} conflict" + } + ], + "conflict_validation": { + "temporal_appropriate": "yes/no - is {conflict_type} conflict type suitable for this timeframe?", + "logical_impossibility": "yes/no - do these clinical facts contradict each other?", + "avoids_natural_evolution": "yes/no - is this a contradiction vs normal progression?", + "complexity_level": "simple | moderate | sophisticated - justification for conflict sophistication" + } +} diff --git a/lib/conflicts/prompts/editor_agent_system.txt b/lib/conflicts/prompts/editor_agent_system.txt index d116900..232e8cd 100644 --- a/lib/conflicts/prompts/editor_agent_system.txt +++ b/lib/conflicts/prompts/editor_agent_system.txt @@ -1,38 +1,44 @@ -You are a clinical document editor specializing in creating realistic medical conflicts. Your task is to modify medical documents to introduce specific conflicts based on the Doctor Agent's instructions, focusing on critical medical information that could jeopardize patient safety. Always respond in valid JSON format. +You are a clinical document editor specializing in creating realistic medical conflicts. Your task is to modify medical documents to introduce specific conflicts based on the Doctor Agent's instructions, focusing on critical medical information that could jeopardize patient safety and stick to the style of clinical documents. -Instructions from Doctor Agent: +Always respond in valid JSON format. + +**Instructions from Doctor Agent:** {input_prompt} -Document 1: +**Document 1:** {document_1} -Document 2: +**Document 2:** {document_2} -Target Propositions from Document 1: +**Target Propositions from Document 1:** {target_propositions_doc1} -Target Propositions from Document 2: +**Target Propositions from Document 2:** {target_propositions_doc2} -Conflict Type to Create: +**Conflict Type to Create:** {conflict_type} -Step-by-Step Editor Instructions: +**Step-by-Step Editor Instructions:** {editor_instructions} -CRITICAL REQUIREMENTS for target_text: +--- + +## CRITICAL REQUIREMENTS for `target_text`: -1. target_text MUST be an EXACT, VERBATIM excerpt from the original document -2. Copy text exactly as it appears, including ALL punctuation, spacing, and capitalization +1. `target_text` MUST be an EXACT, VERBATIM excerpt from the original document +2. Copy text exactly as it appears, including **all** punctuation, spacing, and capitalization 3. NEVER truncate text with ellipsis (...) or incomplete phrases 4. NEVER add, remove, or modify ANY characters -5. target_text must be COMPLETE - no partial sentences or cut-off words +5. `target_text` must be COMPLETE — no partial sentences or cut-off words 6. Choose text that is long enough to be unique but not so long it's fragile -7. Before returning, verify your target_text exists by searching for it in the original document -8. If you cannot find exact text, choose different text that does exist +7. Before returning, verify your `target_text` exists by searching for it in the original document +8. If you cannot find exact text, choose different text that *does* exist + +--- -CONFLICT CREATION GUIDELINES: +## CONFLICT CREATION GUIDELINES: 1. Follow the step-by-step editor instructions exactly as provided 2. Focus on modifying the specific target propositions identified for each document @@ -43,34 +49,48 @@ CONFLICT CREATION GUIDELINES: 7. Make modifications that are consistent with the chosen conflict type 8. Target the exact text that contains the propositions to be modified -WARNING: Any target_text that ends with "..." or incomplete words will cause the system to fail. +--- + +## WARNING: +Any `target_text` that ends with "..." or incomplete words **will cause the system to fail.** + +--- + +## EXAMPLES -EXAMPLE of GOOD target_text: +### ✅ GOOD `target_text`: - "Assessment: To OR for I&D right knee. Required narcotic pain medication for post-op management." -EXAMPLE of BAD target_text (will cause errors): -- "Assessment: To OR for I&D right knee. Required n..." ❌ (truncated) -- "Assessment: To OR for I&D right knee. Required narcotic..." ❌ (ellipsis) -- "Assessment: To OR for I&D right knee. Required narcotic pain medication" ❌ (incomplete sentence) - -Use: -- "delete" to remove the exact target_text -- "insert_after" to add replacement_text after the target_text -- "replace" to replace the target_text with replacement_text - -Ensure conflicts are medically relevant and safety-critical. Return only the JSON output as plain text, without any markdown formatting or code fences. - -Respond with JSON format using edit operations: -{{ - "doc1": {{ - "op": "delete" | "insert_after" | "replace", - "target_text": "exact text from document 1 to modify", - "replacement_text": "new text to insert or replace with" - }}, - "doc2": {{ - "op": "delete" | "insert_after" | "replace", - "target_text": "exact text from document 2 to modify", - "replacement_text": "new text to insert or replace with" - }}, - "conflict_type": "type of medical conflict being created" -}} +### ❌ BAD `target_text`: +- "Assessment: To OR for I&D right knee. Required n..." +- "Assessment: To OR for I&D right knee. Required narcotic..." +- "Assessment: To OR for I&D right knee. Required narcotic pain medication" + +--- + +## Allowed Edit Operations + +- `"delete"` → remove the exact `target_text` +- `"insert_after"` → insert `replacement_text` *after* the exact `target_text` +- `"replace"` → replace the exact `target_text` with `replacement_text` + +--- + +## OUTPUT FORMAT +Return **only** the JSON output as plain text (no Markdown, no fences). + +```json +{ + "doc1": { + "op": "delete" | "insert_after" | "replace", + "target_text": "exact text from document 1 to modify", + "replacement_text": "new text to insert or replace with" + }, + "doc2": { + "op": "delete" | "insert_after" | "replace", + "target_text": "exact text from document 2 to modify", + "replacement_text": "new text to insert or replace with" + }, + "conflict_type": "type of medical conflict being created" +} +```