empathy-framework 4.6.6__py3-none-any.whl → 4.7.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (273) hide show
  1. empathy_framework-4.7.1.dist-info/METADATA +690 -0
  2. empathy_framework-4.7.1.dist-info/RECORD +379 -0
  3. {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.1.dist-info}/top_level.txt +1 -2
  4. empathy_healthcare_plugin/monitors/monitoring/__init__.py +9 -9
  5. empathy_llm_toolkit/agent_factory/__init__.py +6 -6
  6. empathy_llm_toolkit/agent_factory/adapters/wizard_adapter.py +7 -10
  7. empathy_llm_toolkit/agents_md/__init__.py +22 -0
  8. empathy_llm_toolkit/agents_md/loader.py +218 -0
  9. empathy_llm_toolkit/agents_md/parser.py +271 -0
  10. empathy_llm_toolkit/agents_md/registry.py +307 -0
  11. empathy_llm_toolkit/commands/__init__.py +51 -0
  12. empathy_llm_toolkit/commands/context.py +375 -0
  13. empathy_llm_toolkit/commands/loader.py +301 -0
  14. empathy_llm_toolkit/commands/models.py +231 -0
  15. empathy_llm_toolkit/commands/parser.py +371 -0
  16. empathy_llm_toolkit/commands/registry.py +429 -0
  17. empathy_llm_toolkit/config/__init__.py +8 -8
  18. empathy_llm_toolkit/config/unified.py +3 -7
  19. empathy_llm_toolkit/context/__init__.py +22 -0
  20. empathy_llm_toolkit/context/compaction.py +455 -0
  21. empathy_llm_toolkit/context/manager.py +434 -0
  22. empathy_llm_toolkit/hooks/__init__.py +24 -0
  23. empathy_llm_toolkit/hooks/config.py +306 -0
  24. empathy_llm_toolkit/hooks/executor.py +289 -0
  25. empathy_llm_toolkit/hooks/registry.py +302 -0
  26. empathy_llm_toolkit/hooks/scripts/__init__.py +39 -0
  27. empathy_llm_toolkit/hooks/scripts/evaluate_session.py +201 -0
  28. empathy_llm_toolkit/hooks/scripts/first_time_init.py +285 -0
  29. empathy_llm_toolkit/hooks/scripts/pre_compact.py +207 -0
  30. empathy_llm_toolkit/hooks/scripts/session_end.py +183 -0
  31. empathy_llm_toolkit/hooks/scripts/session_start.py +163 -0
  32. empathy_llm_toolkit/hooks/scripts/suggest_compact.py +225 -0
  33. empathy_llm_toolkit/learning/__init__.py +30 -0
  34. empathy_llm_toolkit/learning/evaluator.py +438 -0
  35. empathy_llm_toolkit/learning/extractor.py +514 -0
  36. empathy_llm_toolkit/learning/storage.py +560 -0
  37. empathy_llm_toolkit/providers.py +4 -11
  38. empathy_llm_toolkit/security/__init__.py +17 -17
  39. empathy_llm_toolkit/utils/tokens.py +2 -5
  40. empathy_os/__init__.py +202 -70
  41. empathy_os/cache_monitor.py +5 -3
  42. empathy_os/cli/__init__.py +11 -55
  43. empathy_os/cli/__main__.py +29 -15
  44. empathy_os/cli/commands/inspection.py +21 -12
  45. empathy_os/cli/commands/memory.py +4 -12
  46. empathy_os/cli/commands/profiling.py +198 -0
  47. empathy_os/cli/commands/utilities.py +27 -7
  48. empathy_os/cli.py +28 -57
  49. empathy_os/cli_unified.py +525 -1164
  50. empathy_os/cost_tracker.py +9 -3
  51. empathy_os/dashboard/server.py +200 -2
  52. empathy_os/hot_reload/__init__.py +7 -7
  53. empathy_os/hot_reload/config.py +6 -7
  54. empathy_os/hot_reload/integration.py +35 -35
  55. empathy_os/hot_reload/reloader.py +57 -57
  56. empathy_os/hot_reload/watcher.py +28 -28
  57. empathy_os/hot_reload/websocket.py +2 -2
  58. empathy_os/memory/__init__.py +11 -4
  59. empathy_os/memory/claude_memory.py +1 -1
  60. empathy_os/memory/cross_session.py +8 -12
  61. empathy_os/memory/edges.py +6 -6
  62. empathy_os/memory/file_session.py +770 -0
  63. empathy_os/memory/graph.py +30 -30
  64. empathy_os/memory/nodes.py +6 -6
  65. empathy_os/memory/short_term.py +15 -9
  66. empathy_os/memory/unified.py +606 -140
  67. empathy_os/meta_workflows/agent_creator.py +3 -9
  68. empathy_os/meta_workflows/cli_meta_workflows.py +113 -53
  69. empathy_os/meta_workflows/form_engine.py +6 -18
  70. empathy_os/meta_workflows/intent_detector.py +64 -24
  71. empathy_os/meta_workflows/models.py +3 -1
  72. empathy_os/meta_workflows/pattern_learner.py +13 -31
  73. empathy_os/meta_workflows/plan_generator.py +55 -47
  74. empathy_os/meta_workflows/session_context.py +2 -3
  75. empathy_os/meta_workflows/workflow.py +20 -51
  76. empathy_os/models/cli.py +2 -2
  77. empathy_os/models/tasks.py +1 -2
  78. empathy_os/models/telemetry.py +4 -1
  79. empathy_os/models/token_estimator.py +3 -1
  80. empathy_os/monitoring/alerts.py +938 -9
  81. empathy_os/monitoring/alerts_cli.py +346 -183
  82. empathy_os/orchestration/execution_strategies.py +12 -29
  83. empathy_os/orchestration/pattern_learner.py +20 -26
  84. empathy_os/orchestration/real_tools.py +6 -15
  85. empathy_os/platform_utils.py +2 -1
  86. empathy_os/plugins/__init__.py +2 -2
  87. empathy_os/plugins/base.py +64 -64
  88. empathy_os/plugins/registry.py +32 -32
  89. empathy_os/project_index/index.py +49 -15
  90. empathy_os/project_index/models.py +1 -2
  91. empathy_os/project_index/reports.py +1 -1
  92. empathy_os/project_index/scanner.py +1 -0
  93. empathy_os/redis_memory.py +10 -7
  94. empathy_os/resilience/__init__.py +1 -1
  95. empathy_os/resilience/health.py +10 -10
  96. empathy_os/routing/__init__.py +7 -7
  97. empathy_os/routing/chain_executor.py +37 -37
  98. empathy_os/routing/classifier.py +36 -36
  99. empathy_os/routing/smart_router.py +40 -40
  100. empathy_os/routing/{wizard_registry.py → workflow_registry.py} +47 -47
  101. empathy_os/scaffolding/__init__.py +8 -8
  102. empathy_os/scaffolding/__main__.py +1 -1
  103. empathy_os/scaffolding/cli.py +28 -28
  104. empathy_os/socratic/__init__.py +3 -19
  105. empathy_os/socratic/ab_testing.py +25 -36
  106. empathy_os/socratic/blueprint.py +38 -38
  107. empathy_os/socratic/cli.py +34 -20
  108. empathy_os/socratic/collaboration.py +30 -28
  109. empathy_os/socratic/domain_templates.py +9 -1
  110. empathy_os/socratic/embeddings.py +17 -13
  111. empathy_os/socratic/engine.py +135 -70
  112. empathy_os/socratic/explainer.py +70 -60
  113. empathy_os/socratic/feedback.py +24 -19
  114. empathy_os/socratic/forms.py +15 -10
  115. empathy_os/socratic/generator.py +51 -35
  116. empathy_os/socratic/llm_analyzer.py +25 -23
  117. empathy_os/socratic/mcp_server.py +99 -159
  118. empathy_os/socratic/session.py +19 -13
  119. empathy_os/socratic/storage.py +98 -67
  120. empathy_os/socratic/success.py +38 -27
  121. empathy_os/socratic/visual_editor.py +51 -39
  122. empathy_os/socratic/web_ui.py +99 -66
  123. empathy_os/telemetry/cli.py +3 -1
  124. empathy_os/telemetry/usage_tracker.py +1 -3
  125. empathy_os/test_generator/__init__.py +3 -3
  126. empathy_os/test_generator/cli.py +28 -28
  127. empathy_os/test_generator/generator.py +64 -66
  128. empathy_os/test_generator/risk_analyzer.py +11 -11
  129. empathy_os/vscode_bridge 2.py +173 -0
  130. empathy_os/vscode_bridge.py +173 -0
  131. empathy_os/workflows/__init__.py +212 -120
  132. empathy_os/workflows/batch_processing.py +8 -24
  133. empathy_os/workflows/bug_predict.py +1 -1
  134. empathy_os/workflows/code_review.py +20 -5
  135. empathy_os/workflows/code_review_pipeline.py +13 -8
  136. empathy_os/workflows/keyboard_shortcuts/workflow.py +6 -2
  137. empathy_os/workflows/manage_documentation.py +1 -0
  138. empathy_os/workflows/orchestrated_health_check.py +6 -11
  139. empathy_os/workflows/orchestrated_release_prep.py +3 -3
  140. empathy_os/workflows/pr_review.py +18 -10
  141. empathy_os/workflows/progressive/README 2.md +454 -0
  142. empathy_os/workflows/progressive/__init__ 2.py +92 -0
  143. empathy_os/workflows/progressive/__init__.py +2 -12
  144. empathy_os/workflows/progressive/cli 2.py +242 -0
  145. empathy_os/workflows/progressive/cli.py +14 -37
  146. empathy_os/workflows/progressive/core 2.py +488 -0
  147. empathy_os/workflows/progressive/core.py +12 -12
  148. empathy_os/workflows/progressive/orchestrator 2.py +701 -0
  149. empathy_os/workflows/progressive/orchestrator.py +166 -144
  150. empathy_os/workflows/progressive/reports 2.py +528 -0
  151. empathy_os/workflows/progressive/reports.py +22 -31
  152. empathy_os/workflows/progressive/telemetry 2.py +280 -0
  153. empathy_os/workflows/progressive/telemetry.py +8 -14
  154. empathy_os/workflows/progressive/test_gen 2.py +514 -0
  155. empathy_os/workflows/progressive/test_gen.py +29 -48
  156. empathy_os/workflows/progressive/workflow 2.py +628 -0
  157. empathy_os/workflows/progressive/workflow.py +31 -70
  158. empathy_os/workflows/release_prep.py +21 -6
  159. empathy_os/workflows/release_prep_crew.py +1 -0
  160. empathy_os/workflows/secure_release.py +13 -6
  161. empathy_os/workflows/security_audit.py +8 -3
  162. empathy_os/workflows/test_coverage_boost_crew.py +3 -2
  163. empathy_os/workflows/test_maintenance_crew.py +1 -0
  164. empathy_os/workflows/test_runner.py +16 -12
  165. empathy_software_plugin/SOFTWARE_PLUGIN_README.md +25 -703
  166. empathy_software_plugin/cli.py +0 -122
  167. patterns/README.md +119 -0
  168. patterns/__init__.py +95 -0
  169. patterns/behavior.py +298 -0
  170. patterns/code_review_memory.json +441 -0
  171. patterns/core.py +97 -0
  172. patterns/debugging.json +3763 -0
  173. patterns/empathy.py +268 -0
  174. patterns/health_check_memory.json +505 -0
  175. patterns/input.py +161 -0
  176. patterns/memory_graph.json +8 -0
  177. patterns/refactoring_memory.json +1113 -0
  178. patterns/registry.py +663 -0
  179. patterns/security_memory.json +8 -0
  180. patterns/structural.py +415 -0
  181. patterns/validation.py +194 -0
  182. coach_wizards/__init__.py +0 -45
  183. coach_wizards/accessibility_wizard.py +0 -91
  184. coach_wizards/api_wizard.py +0 -91
  185. coach_wizards/base_wizard.py +0 -209
  186. coach_wizards/cicd_wizard.py +0 -91
  187. coach_wizards/code_reviewer_README.md +0 -60
  188. coach_wizards/code_reviewer_wizard.py +0 -180
  189. coach_wizards/compliance_wizard.py +0 -91
  190. coach_wizards/database_wizard.py +0 -91
  191. coach_wizards/debugging_wizard.py +0 -91
  192. coach_wizards/documentation_wizard.py +0 -91
  193. coach_wizards/generate_wizards.py +0 -347
  194. coach_wizards/localization_wizard.py +0 -173
  195. coach_wizards/migration_wizard.py +0 -91
  196. coach_wizards/monitoring_wizard.py +0 -91
  197. coach_wizards/observability_wizard.py +0 -91
  198. coach_wizards/performance_wizard.py +0 -91
  199. coach_wizards/prompt_engineering_wizard.py +0 -661
  200. coach_wizards/refactoring_wizard.py +0 -91
  201. coach_wizards/scaling_wizard.py +0 -90
  202. coach_wizards/security_wizard.py +0 -92
  203. coach_wizards/testing_wizard.py +0 -91
  204. empathy_framework-4.6.6.dist-info/METADATA +0 -1597
  205. empathy_framework-4.6.6.dist-info/RECORD +0 -410
  206. empathy_llm_toolkit/wizards/__init__.py +0 -43
  207. empathy_llm_toolkit/wizards/base_wizard.py +0 -364
  208. empathy_llm_toolkit/wizards/customer_support_wizard.py +0 -190
  209. empathy_llm_toolkit/wizards/healthcare_wizard.py +0 -378
  210. empathy_llm_toolkit/wizards/patient_assessment_README.md +0 -64
  211. empathy_llm_toolkit/wizards/patient_assessment_wizard.py +0 -193
  212. empathy_llm_toolkit/wizards/technology_wizard.py +0 -209
  213. empathy_os/wizard_factory_cli.py +0 -170
  214. empathy_software_plugin/wizards/__init__.py +0 -42
  215. empathy_software_plugin/wizards/advanced_debugging_wizard.py +0 -395
  216. empathy_software_plugin/wizards/agent_orchestration_wizard.py +0 -511
  217. empathy_software_plugin/wizards/ai_collaboration_wizard.py +0 -503
  218. empathy_software_plugin/wizards/ai_context_wizard.py +0 -441
  219. empathy_software_plugin/wizards/ai_documentation_wizard.py +0 -503
  220. empathy_software_plugin/wizards/base_wizard.py +0 -288
  221. empathy_software_plugin/wizards/book_chapter_wizard.py +0 -519
  222. empathy_software_plugin/wizards/code_review_wizard.py +0 -604
  223. empathy_software_plugin/wizards/debugging/__init__.py +0 -50
  224. empathy_software_plugin/wizards/debugging/bug_risk_analyzer.py +0 -414
  225. empathy_software_plugin/wizards/debugging/config_loaders.py +0 -446
  226. empathy_software_plugin/wizards/debugging/fix_applier.py +0 -469
  227. empathy_software_plugin/wizards/debugging/language_patterns.py +0 -385
  228. empathy_software_plugin/wizards/debugging/linter_parsers.py +0 -470
  229. empathy_software_plugin/wizards/debugging/verification.py +0 -369
  230. empathy_software_plugin/wizards/enhanced_testing_wizard.py +0 -537
  231. empathy_software_plugin/wizards/memory_enhanced_debugging_wizard.py +0 -816
  232. empathy_software_plugin/wizards/multi_model_wizard.py +0 -501
  233. empathy_software_plugin/wizards/pattern_extraction_wizard.py +0 -422
  234. empathy_software_plugin/wizards/pattern_retriever_wizard.py +0 -400
  235. empathy_software_plugin/wizards/performance/__init__.py +0 -9
  236. empathy_software_plugin/wizards/performance/bottleneck_detector.py +0 -221
  237. empathy_software_plugin/wizards/performance/profiler_parsers.py +0 -278
  238. empathy_software_plugin/wizards/performance/trajectory_analyzer.py +0 -429
  239. empathy_software_plugin/wizards/performance_profiling_wizard.py +0 -305
  240. empathy_software_plugin/wizards/prompt_engineering_wizard.py +0 -425
  241. empathy_software_plugin/wizards/rag_pattern_wizard.py +0 -461
  242. empathy_software_plugin/wizards/security/__init__.py +0 -32
  243. empathy_software_plugin/wizards/security/exploit_analyzer.py +0 -290
  244. empathy_software_plugin/wizards/security/owasp_patterns.py +0 -241
  245. empathy_software_plugin/wizards/security/vulnerability_scanner.py +0 -604
  246. empathy_software_plugin/wizards/security_analysis_wizard.py +0 -322
  247. empathy_software_plugin/wizards/security_learning_wizard.py +0 -740
  248. empathy_software_plugin/wizards/tech_debt_wizard.py +0 -726
  249. empathy_software_plugin/wizards/testing/__init__.py +0 -27
  250. empathy_software_plugin/wizards/testing/coverage_analyzer.py +0 -459
  251. empathy_software_plugin/wizards/testing/quality_analyzer.py +0 -525
  252. empathy_software_plugin/wizards/testing/test_suggester.py +0 -533
  253. empathy_software_plugin/wizards/testing_wizard.py +0 -274
  254. wizards/__init__.py +0 -82
  255. wizards/admission_assessment_wizard.py +0 -644
  256. wizards/care_plan.py +0 -321
  257. wizards/clinical_assessment.py +0 -769
  258. wizards/discharge_planning.py +0 -77
  259. wizards/discharge_summary_wizard.py +0 -468
  260. wizards/dosage_calculation.py +0 -497
  261. wizards/incident_report_wizard.py +0 -454
  262. wizards/medication_reconciliation.py +0 -85
  263. wizards/nursing_assessment.py +0 -171
  264. wizards/patient_education.py +0 -654
  265. wizards/quality_improvement.py +0 -705
  266. wizards/sbar_report.py +0 -324
  267. wizards/sbar_wizard.py +0 -608
  268. wizards/shift_handoff_wizard.py +0 -535
  269. wizards/soap_note_wizard.py +0 -679
  270. wizards/treatment_plan.py +0 -15
  271. {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.1.dist-info}/WHEEL +0 -0
  272. {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.1.dist-info}/entry_points.txt +0 -0
  273. {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.1.dist-info}/licenses/LICENSE +0 -0
wizards/sbar_wizard.py DELETED
@@ -1,608 +0,0 @@
1
- """
2
- SBAR Wizard Router - AI Nurse Florence
3
- Following Wizard Pattern Implementation
4
-
5
- SBAR (Situation, Background, Assessment, Recommendation) documentation wizard
6
- for clinical handoff communication and escalation to physicians.
7
-
8
- This wizard includes a review step where users can preview the AI-enhanced report
9
- before saving it.
10
-
11
- Version: 2.0 - Nov 2025 - 5-step wizard with auto-preview and dictation support
12
- """
13
-
14
- import json
15
- import logging
16
- import os
17
- from datetime import datetime
18
- from typing import Any
19
- from uuid import uuid4
20
-
21
- from fastapi import APIRouter, HTTPException, status
22
- from src.services import get_service
23
- from src.utils.api_responses import create_success_response
24
- from src.utils.config import get_settings
25
-
26
- logger = logging.getLogger(__name__)
27
-
28
- # Settings following coding instructions
29
- settings = get_settings()
30
-
31
- router = APIRouter(
32
- prefix="/wizards/sbar",
33
- tags=["clinical-wizards"],
34
- responses={
35
- 404: {"description": "Wizard session not found"},
36
- 422: {"description": "Invalid wizard step data"},
37
- 500: {"description": "Wizard processing error"},
38
- },
39
- )
40
-
41
- # Session storage (Redis in production, memory for development)
42
- try:
43
- from src.utils.redis_cache import get_redis_client
44
-
45
- _has_redis = True
46
- logger.info("✅ Redis client module imported for SBAR wizard sessions")
47
- except ImportError:
48
- _has_redis = False
49
- logger.warning("⚠️ Redis unavailable for SBAR wizard - sessions will use memory only")
50
-
51
- _wizard_sessions: dict[str, dict[str, Any]] = {}
52
-
53
- # Log Redis configuration at module load
54
- redis_url = os.getenv("REDIS_URL")
55
- if redis_url:
56
- logger.info(f"🔧 REDIS_URL environment variable detected (starts with: {redis_url[:15]}...)")
57
- else:
58
- logger.warning(
59
- "⚠️ REDIS_URL environment variable NOT SET - sessions will be lost between workers"
60
- )
61
-
62
-
63
- # SBAR wizard steps - 5 steps total
64
- SBAR_STEPS = {
65
- 1: {
66
- "step": 1,
67
- "title": "Situation",
68
- "prompt": "Describe the current patient situation",
69
- "fields": [
70
- "patient_condition",
71
- "immediate_concerns",
72
- "vital_signs",
73
- ],
74
- "help_text": "What is happening right now with the patient? Include current condition, vital signs, and immediate concerns.",
75
- },
76
- 2: {
77
- "step": 2,
78
- "title": "Background",
79
- "prompt": "Provide relevant clinical background",
80
- "fields": [
81
- "medical_history",
82
- "current_treatments",
83
- "baseline_condition",
84
- ],
85
- "help_text": "What is the clinical context? Include pertinent medical history, current treatments, and baseline condition.",
86
- },
87
- 3: {
88
- "step": 3,
89
- "title": "Assessment",
90
- "prompt": "Your professional clinical assessment",
91
- "fields": [
92
- "clinical_assessment",
93
- "primary_concerns",
94
- "risk_factors",
95
- ],
96
- "help_text": "What do you think is happening? Include your nursing assessment, primary concerns, and risk factors.",
97
- },
98
- 4: {
99
- "step": 4,
100
- "title": "Recommendation",
101
- "prompt": "What actions do you recommend?",
102
- "fields": [
103
- "recommendations",
104
- "requested_actions",
105
- "timeline",
106
- ],
107
- "help_text": "What needs to be done? Include specific recommendations, requested actions, and urgency timeline.",
108
- },
109
- 5: {
110
- "step": 5,
111
- "title": "Review & Enhance",
112
- "prompt": "Review and enhance your SBAR report with AI",
113
- "fields": ["review_complete", "generate_enhanced"],
114
- "help_text": "Review all sections. Click 'Generate Enhanced Report' to see AI suggestions before saving.",
115
- "is_review_step": True,
116
- },
117
- }
118
-
119
-
120
- async def _store_wizard_session(wizard_id: str, session_data: dict[str, Any]):
121
- """Store wizard session in Redis or memory."""
122
- if _has_redis:
123
- try:
124
- redis_client = await get_redis_client()
125
- if redis_client:
126
- await redis_client.setex(
127
- f"sbar_wizard:{wizard_id}",
128
- 3600, # 1 hour expiry
129
- json.dumps(session_data),
130
- )
131
- return
132
- except Exception as e:
133
- logger.warning(f"Failed to store session in Redis: {e}")
134
-
135
- # Fallback to memory
136
- _wizard_sessions[wizard_id] = session_data
137
-
138
-
139
- async def _get_wizard_session(wizard_id: str) -> dict[str, Any] | None:
140
- """Retrieve wizard session from Redis or memory."""
141
- if _has_redis:
142
- try:
143
- redis_client = await get_redis_client()
144
- if redis_client:
145
- data = await redis_client.get(f"sbar_wizard:{wizard_id}")
146
- if data:
147
- return json.loads(data)
148
- except Exception as e:
149
- logger.warning(f"Failed to retrieve session from Redis: {e}")
150
-
151
- # Fallback to memory
152
- return _wizard_sessions.get(wizard_id)
153
-
154
-
155
- def _get_step_data(step_number: int) -> dict[str, Any]:
156
- """Get step configuration data."""
157
- if step_number not in SBAR_STEPS:
158
- raise ValueError(f"Invalid step number: {step_number}")
159
-
160
- return SBAR_STEPS[step_number]
161
-
162
-
163
- @router.post(
164
- "/start",
165
- summary="Start SBAR Wizard",
166
- description="Initialize a new SBAR documentation workflow for clinical handoff communication.",
167
- )
168
- async def start_sbar_wizard():
169
- """Start SBAR wizard following Wizard Pattern Implementation."""
170
- try:
171
- wizard_id = str(uuid4())
172
-
173
- session_data = {
174
- "wizard_id": wizard_id,
175
- "wizard_type": "sbar",
176
- "current_step": 1,
177
- "total_steps": 5,
178
- "collected_data": {},
179
- "created_at": datetime.now().isoformat(),
180
- "updated_at": datetime.now().isoformat(),
181
- }
182
-
183
- # Store session
184
- await _store_wizard_session(wizard_id, session_data)
185
-
186
- # Get first step prompt
187
- step_data = _get_step_data(1)
188
-
189
- response_data = {
190
- "wizard_session": session_data,
191
- "current_step": step_data,
192
- "progress": {"current": 1, "total": 5, "percentage": 20},
193
- }
194
-
195
- return create_success_response(
196
- data=response_data, message="SBAR wizard started successfully"
197
- )
198
-
199
- except Exception as e:
200
- logger.error(f"Failed to start SBAR wizard: {e}", exc_info=True)
201
- raise HTTPException(
202
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
203
- detail=f"Failed to start SBAR wizard: {str(e)}",
204
- )
205
-
206
-
207
- @router.post(
208
- "/{wizard_id}/step",
209
- summary="Submit SBAR wizard step",
210
- description="Submit data for current step and advance to next step in SBAR workflow.",
211
- )
212
- async def submit_sbar_step(wizard_id: str, step_data: dict[str, Any]):
213
- """Submit step data and advance wizard."""
214
- try:
215
- # Get session
216
- session = await _get_wizard_session(wizard_id)
217
- if not session:
218
- raise HTTPException(
219
- status_code=status.HTTP_404_NOT_FOUND,
220
- detail=f"Wizard session {wizard_id} not found",
221
- )
222
-
223
- # Validate step number
224
- current_step = session["current_step"]
225
- if step_data.get("step") != current_step:
226
- raise HTTPException(
227
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
228
- detail=f"Expected step {current_step}, got {step_data.get('step')}",
229
- )
230
-
231
- # Store collected data
232
- session["collected_data"][f"step_{current_step}"] = step_data.get("data", {})
233
- session["updated_at"] = datetime.now().isoformat()
234
-
235
- # Advance to next step or complete
236
- if current_step < session["total_steps"]:
237
- session["current_step"] += 1
238
- await _store_wizard_session(wizard_id, session)
239
-
240
- next_step_data = _get_step_data(session["current_step"])
241
-
242
- # If next step is review step (step 5), generate and include the SBAR report
243
- if session["current_step"] == 5:
244
- # Auto-generate SBAR report for preview
245
- sbar_report = await _generate_sbar_report(wizard_id, session["collected_data"])
246
- next_step_data["sbar_report"] = sbar_report
247
- next_step_data["review_data"] = {
248
- "situation": session["collected_data"].get("step_1", {}),
249
- "background": session["collected_data"].get("step_2", {}),
250
- "assessment": session["collected_data"].get("step_3", {}),
251
- "recommendation": session["collected_data"].get("step_4", {}),
252
- }
253
-
254
- return create_success_response(
255
- data={
256
- "wizard_session": session,
257
- "current_step": next_step_data,
258
- "progress": {
259
- "current": session["current_step"],
260
- "total": session["total_steps"],
261
- "percentage": (session["current_step"] / session["total_steps"]) * 100,
262
- },
263
- },
264
- message=f"Step {current_step} completed",
265
- )
266
- else:
267
- # Wizard complete on step 5 - mark as complete and return report
268
- sbar_report = await _generate_sbar_report(wizard_id, session["collected_data"])
269
-
270
- session["completed_at"] = datetime.now().isoformat()
271
- session["final_report"] = sbar_report
272
- await _store_wizard_session(wizard_id, session)
273
-
274
- return create_success_response(
275
- data={
276
- "wizard_session": session,
277
- "sbar_report": sbar_report,
278
- "completed": True,
279
- },
280
- message="SBAR documentation completed successfully",
281
- )
282
-
283
- except HTTPException:
284
- raise
285
- except Exception as e:
286
- logger.error(f"Failed to process wizard step: {e}", exc_info=True)
287
- raise HTTPException(
288
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
289
- detail=f"Failed to process wizard step: {str(e)}",
290
- )
291
-
292
-
293
- @router.post(
294
- "/{wizard_id}/enhance",
295
- summary="Generate enhanced SBAR report for review",
296
- description="Generate AI-enhanced SBAR report for user to review before saving.",
297
- )
298
- async def enhance_sbar_report(wizard_id: str):
299
- """
300
- Generate enhanced SBAR report with AI for review.
301
- This does NOT save the report - user must call /save endpoint after reviewing.
302
- """
303
- try:
304
- session = await _get_wizard_session(wizard_id)
305
- if not session:
306
- raise HTTPException(
307
- status_code=status.HTTP_404_NOT_FOUND,
308
- detail=f"Wizard session {wizard_id} not found",
309
- )
310
-
311
- # Verify we're on step 5
312
- if session["current_step"] != 5:
313
- raise HTTPException(
314
- status_code=status.HTTP_400_BAD_REQUEST,
315
- detail=f"Can only enhance report on final step. Current step: {session['current_step']}",
316
- )
317
-
318
- # Generate SBAR report with AI enhancement
319
- sbar_report = await _generate_sbar_report(wizard_id, session["collected_data"])
320
-
321
- # Store enhanced report in session for review (but don't mark as completed yet)
322
- session["enhanced_report"] = sbar_report
323
- session["enhanced_at"] = datetime.now().isoformat()
324
- await _store_wizard_session(wizard_id, session)
325
-
326
- return create_success_response(
327
- data={
328
- "wizard_session": session,
329
- "sbar_report": sbar_report,
330
- "message": "Review the enhanced report below. Click 'Save Report' to finalize.",
331
- },
332
- message="Enhanced SBAR report generated for review",
333
- )
334
-
335
- except HTTPException:
336
- raise
337
- except Exception as e:
338
- logger.error(f"Failed to enhance SBAR report: {e}", exc_info=True)
339
- raise HTTPException(
340
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
341
- detail=f"Failed to enhance SBAR report: {str(e)}",
342
- )
343
-
344
-
345
- @router.post(
346
- "/{wizard_id}/save",
347
- summary="Save reviewed SBAR report",
348
- description="Save the enhanced SBAR report after user has reviewed it.",
349
- )
350
- async def save_sbar_report(wizard_id: str):
351
- """
352
- Save the enhanced SBAR report after user review.
353
- """
354
- try:
355
- session = await _get_wizard_session(wizard_id)
356
- if not session:
357
- raise HTTPException(
358
- status_code=status.HTTP_404_NOT_FOUND,
359
- detail=f"Wizard session {wizard_id} not found",
360
- )
361
-
362
- # Verify enhanced report exists
363
- if "enhanced_report" not in session:
364
- raise HTTPException(
365
- status_code=status.HTTP_400_BAD_REQUEST,
366
- detail="No enhanced report found. Generate enhanced report first.",
367
- )
368
-
369
- # Mark as completed
370
- session["completed_at"] = datetime.now().isoformat()
371
- session["final_report"] = session["enhanced_report"]
372
- await _store_wizard_session(wizard_id, session)
373
-
374
- return create_success_response(
375
- data={
376
- "wizard_session": session,
377
- "sbar_report": session["final_report"],
378
- "completed": True,
379
- },
380
- message="SBAR report saved successfully",
381
- )
382
-
383
- except HTTPException:
384
- raise
385
- except Exception as e:
386
- logger.error(f"Failed to save SBAR report: {e}", exc_info=True)
387
- raise HTTPException(
388
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
389
- detail=f"Failed to save SBAR report: {str(e)}",
390
- )
391
-
392
-
393
- @router.get(
394
- "/{wizard_id}/report",
395
- summary="Get SBAR report",
396
- description="Retrieve the completed SBAR report.",
397
- )
398
- async def get_sbar_report(wizard_id: str):
399
- """Get completed SBAR report."""
400
- try:
401
- session = await _get_wizard_session(wizard_id)
402
- if not session:
403
- raise HTTPException(
404
- status_code=status.HTTP_404_NOT_FOUND,
405
- detail=f"Wizard session {wizard_id} not found",
406
- )
407
-
408
- if "final_report" not in session:
409
- raise HTTPException(
410
- status_code=status.HTTP_400_BAD_REQUEST,
411
- detail="SBAR report not yet saved",
412
- )
413
-
414
- return create_success_response(
415
- data={"sbar_report": session["final_report"]},
416
- message="SBAR report retrieved",
417
- )
418
-
419
- except HTTPException:
420
- raise
421
- except Exception as e:
422
- logger.error(f"Failed to retrieve report: {e}", exc_info=True)
423
- raise HTTPException(
424
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
425
- detail=f"Failed to retrieve report: {str(e)}",
426
- )
427
-
428
-
429
- async def _generate_sbar_report(wizard_id: str, collected_data: dict[str, Any]) -> dict[str, Any]:
430
- """Generate SBAR report from collected data with AI enhancement."""
431
- logger.info(f"Generating SBAR report for wizard {wizard_id}")
432
-
433
- # Extract collected data
434
- step1 = collected_data.get("step_1", {})
435
- step2 = collected_data.get("step_2", {})
436
- step3 = collected_data.get("step_3", {})
437
- step4 = collected_data.get("step_4", {})
438
-
439
- logger.debug(f"SBAR data - Steps collected: {list(collected_data.keys())}")
440
-
441
- # Compile all steps into structured SBAR report
442
- report = {
443
- "report_type": "sbar",
444
- "generated_at": datetime.now().isoformat(),
445
- "sections": {
446
- "situation": step1,
447
- "background": step2,
448
- "assessment": step3,
449
- "recommendation": step4,
450
- },
451
- "situation": step1,
452
- "background": step2,
453
- "assessment": step3,
454
- "recommendation": step4,
455
- "formatted_report": _format_sbar_narrative(collected_data),
456
- }
457
-
458
- logger.debug(f"Formatted report length: {len(report['formatted_report'])} chars")
459
-
460
- # Try to enhance with AI
461
- try:
462
- sbar_service = get_service("sbar")
463
- if sbar_service:
464
- logger.info(f"Enhancing SBAR report for wizard {wizard_id}")
465
-
466
- enhancement_result = await sbar_service.enhance_sbar_report(report)
467
-
468
- if enhancement_result.get("enhanced"):
469
- report["ai_enhanced"] = True
470
- report["enhanced_report"] = enhancement_result.get("enhanced_report")
471
- report["model_used"] = enhancement_result.get("model")
472
- report["ai_usage"] = enhancement_result.get("usage")
473
- logger.info(f"SBAR report enhanced with {enhancement_result.get('model')}")
474
- else:
475
- report["ai_enhanced"] = False
476
- report["enhancement_note"] = enhancement_result.get(
477
- "note", "Enhancement unavailable"
478
- )
479
- logger.warning(f"SBAR enhancement unavailable: {enhancement_result.get('note')}")
480
- else:
481
- logger.warning("SBAR service not available")
482
- report["ai_enhanced"] = False
483
- report["enhancement_note"] = "SBAR service not available"
484
-
485
- except Exception as e:
486
- logger.error(f"Failed to enhance SBAR report: {e}", exc_info=True)
487
- report["ai_enhanced"] = False
488
- report["enhancement_error"] = str(e)
489
-
490
- return report
491
-
492
-
493
- def _format_sbar_narrative(collected_data: dict[str, Any]) -> str:
494
- """Format collected data into narrative SBAR report."""
495
- sections = []
496
-
497
- # Header
498
- sections.append("=" * 60)
499
- sections.append("SBAR CLINICAL COMMUNICATION REPORT")
500
- sections.append("=" * 60)
501
- sections.append("")
502
-
503
- # Situation
504
- step1 = collected_data.get("step_1", {})
505
- sections.append("SITUATION")
506
- sections.append("-" * 60)
507
- if step1:
508
- patient_condition = step1.get("patient_condition", "")
509
- immediate_concerns = step1.get("immediate_concerns", "")
510
- vital_signs = step1.get("vital_signs", "")
511
-
512
- if patient_condition or immediate_concerns:
513
- narrative = []
514
- if patient_condition:
515
- narrative.append(f"The patient is currently {patient_condition.strip()}.")
516
- if immediate_concerns:
517
- narrative.append(f"Immediate concerns include: {immediate_concerns.strip()}.")
518
- if vital_signs:
519
- narrative.append(f"Current vital signs: {vital_signs.strip()}.")
520
- sections.append(" ".join(narrative))
521
- else:
522
- sections.append("No situation data provided.")
523
- else:
524
- sections.append("No situation data provided.")
525
- sections.append("")
526
-
527
- # Background
528
- step2 = collected_data.get("step_2", {})
529
- sections.append("BACKGROUND")
530
- sections.append("-" * 60)
531
- if step2:
532
- medical_history = step2.get("medical_history", "")
533
- current_treatments = step2.get("current_treatments", "")
534
- baseline_condition = step2.get("baseline_condition", "")
535
-
536
- if medical_history or current_treatments or baseline_condition:
537
- narrative = []
538
- if medical_history:
539
- narrative.append(f"Patient medical history: {medical_history.strip()}.")
540
- if baseline_condition:
541
- narrative.append(f"Baseline condition: {baseline_condition.strip()}.")
542
- if current_treatments:
543
- narrative.append(f"Current treatments include: {current_treatments.strip()}.")
544
- sections.append(" ".join(narrative))
545
- else:
546
- sections.append("No background data provided.")
547
- else:
548
- sections.append("No background data provided.")
549
- sections.append("")
550
-
551
- # Assessment
552
- step3 = collected_data.get("step_3", {})
553
- sections.append("ASSESSMENT")
554
- sections.append("-" * 60)
555
- if step3:
556
- clinical_assessment = step3.get("clinical_assessment", "")
557
- primary_concerns = step3.get("primary_concerns", "")
558
- risk_factors = step3.get("risk_factors", "")
559
-
560
- if clinical_assessment or primary_concerns or risk_factors:
561
- narrative = []
562
- if clinical_assessment:
563
- narrative.append(f"Clinical assessment: {clinical_assessment.strip()}.")
564
- if primary_concerns:
565
- narrative.append(f"Primary concerns: {primary_concerns.strip()}.")
566
- if risk_factors:
567
- narrative.append(f"Risk factors identified: {risk_factors.strip()}.")
568
- sections.append(" ".join(narrative))
569
- else:
570
- sections.append("No assessment data provided.")
571
- else:
572
- sections.append("No assessment data provided.")
573
- sections.append("")
574
-
575
- # Recommendation
576
- step4 = collected_data.get("step_4", {})
577
- sections.append("RECOMMENDATION")
578
- sections.append("-" * 60)
579
- if step4:
580
- recommendations = step4.get("recommendations", "")
581
- requested_actions = step4.get("requested_actions", "")
582
- timeline = step4.get("timeline", "")
583
-
584
- if recommendations or requested_actions or timeline:
585
- narrative = []
586
- if recommendations:
587
- narrative.append(f"Recommended interventions: {recommendations.strip()}.")
588
- if requested_actions:
589
- narrative.append(f"Requested actions: {requested_actions.strip()}.")
590
- if timeline:
591
- narrative.append(f"Timeline: {timeline.strip()}.")
592
- sections.append(" ".join(narrative))
593
- else:
594
- sections.append("No recommendations provided.")
595
- else:
596
- sections.append("No recommendations provided.")
597
- sections.append("")
598
-
599
- sections.append("=" * 60)
600
- sections.append("Educational use only — not medical advice. No PHI stored.")
601
- sections.append(f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
602
- sections.append("=" * 60)
603
-
604
- return "\n".join(sections)
605
-
606
-
607
- # Export router
608
- __all__ = ["router"]