cbt-companion-api / context_builder.py
stanlee47
changes
481624a
"""
Therapeutic Context Builder
Builds context strings to inject into agent system prompts for continuity
"""
import json
def build_patient_context(patient_profile: dict, previous_session: dict = None) -> str:
"""
Build therapeutic context from patient history.
Args:
patient_profile: Patient profile dict from patient_tracker
previous_session: Previous beck_session dict (optional)
Returns:
Formatted context string for agent prompts
"""
ctx_parts = []
ctx_parts.append("=== THERAPEUTIC CONTEXT ===")
# Session history
total_sessions = patient_profile.get('total_beck_sessions', 0)
ctx_parts.append(f"Beck Protocol Sessions Completed: {total_sessions}")
if total_sessions == 0:
ctx_parts.append("This is the patient's FIRST Beck protocol session.")
# Treatment phase
phase = patient_profile.get('current_treatment_phase', 'assessment')
phase_labels = {
'assessment': 'Initial Assessment',
'behavioral_activation': 'Behavioral Activation (Severe Depression)',
'cognitive_restructuring': 'Cognitive Restructuring',
'schema_work': 'Cognitive Restructuring + Schema Exploration',
'relapse_prevention': 'Relapse Prevention & Maintenance'
}
ctx_parts.append(f"Current Phase: {phase_labels.get(phase, phase)}")
# BDI trajectory
bdi_scores = patient_profile.get('bdi_scores', [])
if isinstance(bdi_scores, str):
try:
bdi_scores = json.loads(bdi_scores)
except:
bdi_scores = []
if bdi_scores and len(bdi_scores) > 0:
recent_scores = bdi_scores[-5:] # Last 5 sessions
score_str = " β†’ ".join([str(s.get('score', s) if isinstance(s, dict) else s) for s in recent_scores])
ctx_parts.append(f"BDI Trajectory (last {len(recent_scores)} sessions): {score_str}")
if len(recent_scores) >= 2:
# Calculate trend
try:
latest = recent_scores[-1].get('score') if isinstance(recent_scores[-1], dict) else recent_scores[-1]
previous = recent_scores[-2].get('score') if isinstance(recent_scores[-2], dict) else recent_scores[-2]
change = latest - previous
if change < -3:
ctx_parts.append(" β†’ Improving trend βœ“")
elif change > 3:
ctx_parts.append(" β†’ Worsening trend - needs attention")
else:
ctx_parts.append(" β†’ Stable")
except:
pass
# Core beliefs identified
core_beliefs = patient_profile.get('core_beliefs', [])
if isinstance(core_beliefs, str):
try:
core_beliefs = json.loads(core_beliefs)
except:
core_beliefs = []
if core_beliefs:
ctx_parts.append(f"Core Beliefs Identified: {', '.join(core_beliefs)}")
# Intermediate beliefs
intermediate_beliefs = patient_profile.get('intermediate_beliefs', [])
if isinstance(intermediate_beliefs, str):
try:
intermediate_beliefs = json.loads(intermediate_beliefs)
except:
intermediate_beliefs = []
if intermediate_beliefs:
ctx_parts.append(f"Intermediate Beliefs: {', '.join(intermediate_beliefs[:3])}")
# Recurring distortion patterns
distortions = patient_profile.get('recurring_distortions', {})
if isinstance(distortions, str):
try:
distortions = json.loads(distortions)
except:
distortions = {}
if distortions:
sorted_distortions = sorted(distortions.items(), key=lambda x: x[1], reverse=True)
if sorted_distortions:
top_distortion = sorted_distortions[0]
distortion_labels = {
'G1': 'All-or-nothing thinking',
'G2': 'Overgeneralization',
'G3': 'Mental filter',
'G4': 'Emotional reasoning'
}
ctx_parts.append(f"Most Common Pattern: {distortion_labels.get(top_distortion[0], top_distortion[0])} ({top_distortion[1]}x)")
# Homework status
homework = patient_profile.get('homework_pending')
if homework and homework != 'null':
try:
hw = json.loads(homework) if isinstance(homework, str) else homework
ctx_parts.append(f"Pending Homework: {hw.get('description', 'assigned')}")
except:
pass
# Previous session summary
if previous_session:
ctx_parts.append("\n--- PREVIOUS SESSION ---")
# What they worked on
if previous_session.get('original_thought'):
ctx_parts.append(f"Worked on: \"{previous_session['original_thought'][:100]}...\"")
# Reframe
if previous_session.get('adaptive_thought'):
ctx_parts.append(f"Reframe: \"{previous_session['adaptive_thought'][:100]}...\"")
# Action plan
if previous_session.get('action_plan'):
ctx_parts.append(f"Action Plan: {previous_session['action_plan'][:100]}")
# Improvement
if previous_session.get('belief_improvement'):
ctx_parts.append(f"Belief Improvement: {previous_session['belief_improvement']}%")
# Session summary
if previous_session.get('session_summary_text'):
ctx_parts.append(f"Summary: {previous_session['session_summary_text'][:150]}...")
ctx_parts.append("=== END CONTEXT ===\n")
return "\n".join(ctx_parts)
def build_minimal_context(session_number: int, bdi_score: int = None, severity: str = None) -> str:
"""Build minimal context for early sessions."""
ctx = "=== THERAPEUTIC CONTEXT ===\n"
ctx += f"Session Number: {session_number}\n"
if bdi_score is not None:
ctx += f"BDI-II Score: {bdi_score} ({severity})\n"
if session_number == 1:
ctx += "This is the patient's FIRST Beck protocol session.\n"
ctx += "=== END CONTEXT ===\n"
return ctx
# Test if run directly
if __name__ == "__main__":
print("Testing context builder:\n")
# Mock patient profile
mock_profile = {
'total_beck_sessions': 5,
'current_treatment_phase': 'cognitive_restructuring',
'bdi_scores': [
{'score': 35, 'severity': 'severe'},
{'score': 28, 'severity': 'moderate'},
{'score': 22, 'severity': 'moderate'},
{'score': 18, 'severity': 'mild'},
{'score': 15, 'severity': 'mild'}
],
'core_beliefs': ['I am incompetent', 'I am unlovable'],
'recurring_distortions': {'G1': 8, 'G2': 5, 'G4': 3}
}
mock_previous = {
'original_thought': 'I am a complete failure at my job',
'adaptive_thought': 'I struggle with some tasks but I am learning and improving',
'action_plan': 'Ask for feedback from manager this week',
'belief_improvement': 25
}
context = build_patient_context(mock_profile, mock_previous)
print(context)