empathy-framework 3.7.0__py3-none-any.whl → 3.8.0__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 (274) hide show
  1. coach_wizards/code_reviewer_README.md +60 -0
  2. coach_wizards/code_reviewer_wizard.py +180 -0
  3. {empathy_framework-3.7.0.dist-info → empathy_framework-3.8.0.dist-info}/METADATA +148 -11
  4. empathy_framework-3.8.0.dist-info/RECORD +333 -0
  5. {empathy_framework-3.7.0.dist-info → empathy_framework-3.8.0.dist-info}/top_level.txt +5 -1
  6. empathy_healthcare_plugin/monitors/__init__.py +9 -0
  7. empathy_healthcare_plugin/monitors/clinical_protocol_monitor.py +315 -0
  8. empathy_healthcare_plugin/monitors/monitoring/__init__.py +44 -0
  9. empathy_healthcare_plugin/monitors/monitoring/protocol_checker.py +300 -0
  10. empathy_healthcare_plugin/monitors/monitoring/protocol_loader.py +214 -0
  11. empathy_healthcare_plugin/monitors/monitoring/sensor_parsers.py +306 -0
  12. empathy_healthcare_plugin/monitors/monitoring/trajectory_analyzer.py +389 -0
  13. empathy_llm_toolkit/agent_factory/__init__.py +53 -0
  14. empathy_llm_toolkit/agent_factory/adapters/__init__.py +85 -0
  15. empathy_llm_toolkit/agent_factory/adapters/autogen_adapter.py +312 -0
  16. empathy_llm_toolkit/agent_factory/adapters/crewai_adapter.py +454 -0
  17. empathy_llm_toolkit/agent_factory/adapters/haystack_adapter.py +298 -0
  18. empathy_llm_toolkit/agent_factory/adapters/langchain_adapter.py +362 -0
  19. empathy_llm_toolkit/agent_factory/adapters/langgraph_adapter.py +333 -0
  20. empathy_llm_toolkit/agent_factory/adapters/native.py +228 -0
  21. empathy_llm_toolkit/agent_factory/adapters/wizard_adapter.py +426 -0
  22. empathy_llm_toolkit/agent_factory/base.py +305 -0
  23. empathy_llm_toolkit/agent_factory/crews/__init__.py +67 -0
  24. empathy_llm_toolkit/agent_factory/crews/code_review.py +1113 -0
  25. empathy_llm_toolkit/agent_factory/crews/health_check.py +1246 -0
  26. empathy_llm_toolkit/agent_factory/crews/refactoring.py +1128 -0
  27. empathy_llm_toolkit/agent_factory/crews/security_audit.py +1018 -0
  28. empathy_llm_toolkit/agent_factory/decorators.py +286 -0
  29. empathy_llm_toolkit/agent_factory/factory.py +558 -0
  30. empathy_llm_toolkit/agent_factory/framework.py +192 -0
  31. empathy_llm_toolkit/agent_factory/memory_integration.py +324 -0
  32. empathy_llm_toolkit/agent_factory/resilient.py +320 -0
  33. empathy_llm_toolkit/cli/__init__.py +8 -0
  34. empathy_llm_toolkit/cli/sync_claude.py +487 -0
  35. empathy_llm_toolkit/code_health.py +150 -3
  36. empathy_llm_toolkit/config/__init__.py +29 -0
  37. empathy_llm_toolkit/config/unified.py +295 -0
  38. empathy_llm_toolkit/routing/__init__.py +32 -0
  39. empathy_llm_toolkit/routing/model_router.py +362 -0
  40. empathy_llm_toolkit/security/IMPLEMENTATION_SUMMARY.md +413 -0
  41. empathy_llm_toolkit/security/PHASE2_COMPLETE.md +384 -0
  42. empathy_llm_toolkit/security/PHASE2_SECRETS_DETECTOR_COMPLETE.md +271 -0
  43. empathy_llm_toolkit/security/QUICK_REFERENCE.md +316 -0
  44. empathy_llm_toolkit/security/README.md +262 -0
  45. empathy_llm_toolkit/security/__init__.py +62 -0
  46. empathy_llm_toolkit/security/audit_logger.py +929 -0
  47. empathy_llm_toolkit/security/audit_logger_example.py +152 -0
  48. empathy_llm_toolkit/security/pii_scrubber.py +640 -0
  49. empathy_llm_toolkit/security/secrets_detector.py +678 -0
  50. empathy_llm_toolkit/security/secrets_detector_example.py +304 -0
  51. empathy_llm_toolkit/security/secure_memdocs.py +1192 -0
  52. empathy_llm_toolkit/security/secure_memdocs_example.py +278 -0
  53. empathy_llm_toolkit/wizards/__init__.py +38 -0
  54. empathy_llm_toolkit/wizards/base_wizard.py +364 -0
  55. empathy_llm_toolkit/wizards/customer_support_wizard.py +190 -0
  56. empathy_llm_toolkit/wizards/healthcare_wizard.py +362 -0
  57. empathy_llm_toolkit/wizards/patient_assessment_README.md +64 -0
  58. empathy_llm_toolkit/wizards/patient_assessment_wizard.py +193 -0
  59. empathy_llm_toolkit/wizards/technology_wizard.py +194 -0
  60. empathy_os/__init__.py +52 -52
  61. empathy_os/adaptive/__init__.py +13 -0
  62. empathy_os/adaptive/task_complexity.py +127 -0
  63. empathy_os/cache/__init__.py +117 -0
  64. empathy_os/cache/base.py +166 -0
  65. empathy_os/cache/dependency_manager.py +253 -0
  66. empathy_os/cache/hash_only.py +248 -0
  67. empathy_os/cache/hybrid.py +390 -0
  68. empathy_os/cache/storage.py +282 -0
  69. empathy_os/cli.py +118 -8
  70. empathy_os/cli_unified.py +121 -1
  71. empathy_os/config/__init__.py +63 -0
  72. empathy_os/config/xml_config.py +239 -0
  73. empathy_os/config.py +2 -1
  74. empathy_os/dashboard/__init__.py +15 -0
  75. empathy_os/dashboard/server.py +743 -0
  76. empathy_os/memory/__init__.py +195 -0
  77. empathy_os/memory/claude_memory.py +466 -0
  78. empathy_os/memory/config.py +224 -0
  79. empathy_os/memory/control_panel.py +1298 -0
  80. empathy_os/memory/edges.py +179 -0
  81. empathy_os/memory/graph.py +567 -0
  82. empathy_os/memory/long_term.py +1194 -0
  83. empathy_os/memory/nodes.py +179 -0
  84. empathy_os/memory/redis_bootstrap.py +540 -0
  85. empathy_os/memory/security/__init__.py +31 -0
  86. empathy_os/memory/security/audit_logger.py +930 -0
  87. empathy_os/memory/security/pii_scrubber.py +640 -0
  88. empathy_os/memory/security/secrets_detector.py +678 -0
  89. empathy_os/memory/short_term.py +2119 -0
  90. empathy_os/memory/storage/__init__.py +15 -0
  91. empathy_os/memory/summary_index.py +583 -0
  92. empathy_os/memory/unified.py +619 -0
  93. empathy_os/metrics/__init__.py +12 -0
  94. empathy_os/metrics/prompt_metrics.py +190 -0
  95. empathy_os/models/__init__.py +136 -0
  96. empathy_os/models/__main__.py +13 -0
  97. empathy_os/models/cli.py +655 -0
  98. empathy_os/models/empathy_executor.py +354 -0
  99. empathy_os/models/executor.py +252 -0
  100. empathy_os/models/fallback.py +671 -0
  101. empathy_os/models/provider_config.py +563 -0
  102. empathy_os/models/registry.py +382 -0
  103. empathy_os/models/tasks.py +302 -0
  104. empathy_os/models/telemetry.py +548 -0
  105. empathy_os/models/token_estimator.py +378 -0
  106. empathy_os/models/validation.py +274 -0
  107. empathy_os/monitoring/__init__.py +52 -0
  108. empathy_os/monitoring/alerts.py +23 -0
  109. empathy_os/monitoring/alerts_cli.py +268 -0
  110. empathy_os/monitoring/multi_backend.py +271 -0
  111. empathy_os/monitoring/otel_backend.py +363 -0
  112. empathy_os/optimization/__init__.py +19 -0
  113. empathy_os/optimization/context_optimizer.py +272 -0
  114. empathy_os/plugins/__init__.py +28 -0
  115. empathy_os/plugins/base.py +361 -0
  116. empathy_os/plugins/registry.py +268 -0
  117. empathy_os/project_index/__init__.py +30 -0
  118. empathy_os/project_index/cli.py +335 -0
  119. empathy_os/project_index/crew_integration.py +430 -0
  120. empathy_os/project_index/index.py +425 -0
  121. empathy_os/project_index/models.py +501 -0
  122. empathy_os/project_index/reports.py +473 -0
  123. empathy_os/project_index/scanner.py +538 -0
  124. empathy_os/prompts/__init__.py +61 -0
  125. empathy_os/prompts/config.py +77 -0
  126. empathy_os/prompts/context.py +177 -0
  127. empathy_os/prompts/parser.py +285 -0
  128. empathy_os/prompts/registry.py +313 -0
  129. empathy_os/prompts/templates.py +208 -0
  130. empathy_os/resilience/__init__.py +56 -0
  131. empathy_os/resilience/circuit_breaker.py +256 -0
  132. empathy_os/resilience/fallback.py +179 -0
  133. empathy_os/resilience/health.py +300 -0
  134. empathy_os/resilience/retry.py +209 -0
  135. empathy_os/resilience/timeout.py +135 -0
  136. empathy_os/routing/__init__.py +43 -0
  137. empathy_os/routing/chain_executor.py +433 -0
  138. empathy_os/routing/classifier.py +217 -0
  139. empathy_os/routing/smart_router.py +234 -0
  140. empathy_os/routing/wizard_registry.py +307 -0
  141. empathy_os/trust/__init__.py +28 -0
  142. empathy_os/trust/circuit_breaker.py +579 -0
  143. empathy_os/validation/__init__.py +19 -0
  144. empathy_os/validation/xml_validator.py +281 -0
  145. empathy_os/wizard_factory_cli.py +170 -0
  146. empathy_os/workflows/__init__.py +360 -0
  147. empathy_os/workflows/base.py +1660 -0
  148. empathy_os/workflows/bug_predict.py +962 -0
  149. empathy_os/workflows/code_review.py +960 -0
  150. empathy_os/workflows/code_review_adapters.py +310 -0
  151. empathy_os/workflows/code_review_pipeline.py +720 -0
  152. empathy_os/workflows/config.py +600 -0
  153. empathy_os/workflows/dependency_check.py +648 -0
  154. empathy_os/workflows/document_gen.py +1069 -0
  155. empathy_os/workflows/documentation_orchestrator.py +1205 -0
  156. empathy_os/workflows/health_check.py +679 -0
  157. empathy_os/workflows/keyboard_shortcuts/__init__.py +39 -0
  158. empathy_os/workflows/keyboard_shortcuts/generators.py +386 -0
  159. empathy_os/workflows/keyboard_shortcuts/parsers.py +414 -0
  160. empathy_os/workflows/keyboard_shortcuts/prompts.py +295 -0
  161. empathy_os/workflows/keyboard_shortcuts/schema.py +193 -0
  162. empathy_os/workflows/keyboard_shortcuts/workflow.py +505 -0
  163. empathy_os/workflows/manage_documentation.py +804 -0
  164. empathy_os/workflows/new_sample_workflow1.py +146 -0
  165. empathy_os/workflows/new_sample_workflow1_README.md +150 -0
  166. empathy_os/workflows/perf_audit.py +687 -0
  167. empathy_os/workflows/pr_review.py +748 -0
  168. empathy_os/workflows/progress.py +445 -0
  169. empathy_os/workflows/progress_server.py +322 -0
  170. empathy_os/workflows/refactor_plan.py +693 -0
  171. empathy_os/workflows/release_prep.py +808 -0
  172. empathy_os/workflows/research_synthesis.py +404 -0
  173. empathy_os/workflows/secure_release.py +585 -0
  174. empathy_os/workflows/security_adapters.py +297 -0
  175. empathy_os/workflows/security_audit.py +1046 -0
  176. empathy_os/workflows/step_config.py +234 -0
  177. empathy_os/workflows/test5.py +125 -0
  178. empathy_os/workflows/test5_README.md +158 -0
  179. empathy_os/workflows/test_gen.py +1855 -0
  180. empathy_os/workflows/test_lifecycle.py +526 -0
  181. empathy_os/workflows/test_maintenance.py +626 -0
  182. empathy_os/workflows/test_maintenance_cli.py +590 -0
  183. empathy_os/workflows/test_maintenance_crew.py +821 -0
  184. empathy_os/workflows/xml_enhanced_crew.py +285 -0
  185. empathy_software_plugin/cli/__init__.py +120 -0
  186. empathy_software_plugin/cli/inspect.py +362 -0
  187. empathy_software_plugin/cli.py +3 -1
  188. empathy_software_plugin/wizards/__init__.py +42 -0
  189. empathy_software_plugin/wizards/advanced_debugging_wizard.py +392 -0
  190. empathy_software_plugin/wizards/agent_orchestration_wizard.py +511 -0
  191. empathy_software_plugin/wizards/ai_collaboration_wizard.py +503 -0
  192. empathy_software_plugin/wizards/ai_context_wizard.py +441 -0
  193. empathy_software_plugin/wizards/ai_documentation_wizard.py +503 -0
  194. empathy_software_plugin/wizards/base_wizard.py +288 -0
  195. empathy_software_plugin/wizards/book_chapter_wizard.py +519 -0
  196. empathy_software_plugin/wizards/code_review_wizard.py +606 -0
  197. empathy_software_plugin/wizards/debugging/__init__.py +50 -0
  198. empathy_software_plugin/wizards/debugging/bug_risk_analyzer.py +414 -0
  199. empathy_software_plugin/wizards/debugging/config_loaders.py +442 -0
  200. empathy_software_plugin/wizards/debugging/fix_applier.py +469 -0
  201. empathy_software_plugin/wizards/debugging/language_patterns.py +383 -0
  202. empathy_software_plugin/wizards/debugging/linter_parsers.py +470 -0
  203. empathy_software_plugin/wizards/debugging/verification.py +369 -0
  204. empathy_software_plugin/wizards/enhanced_testing_wizard.py +537 -0
  205. empathy_software_plugin/wizards/memory_enhanced_debugging_wizard.py +816 -0
  206. empathy_software_plugin/wizards/multi_model_wizard.py +501 -0
  207. empathy_software_plugin/wizards/pattern_extraction_wizard.py +422 -0
  208. empathy_software_plugin/wizards/pattern_retriever_wizard.py +400 -0
  209. empathy_software_plugin/wizards/performance/__init__.py +9 -0
  210. empathy_software_plugin/wizards/performance/bottleneck_detector.py +221 -0
  211. empathy_software_plugin/wizards/performance/profiler_parsers.py +278 -0
  212. empathy_software_plugin/wizards/performance/trajectory_analyzer.py +429 -0
  213. empathy_software_plugin/wizards/performance_profiling_wizard.py +305 -0
  214. empathy_software_plugin/wizards/prompt_engineering_wizard.py +425 -0
  215. empathy_software_plugin/wizards/rag_pattern_wizard.py +461 -0
  216. empathy_software_plugin/wizards/security/__init__.py +32 -0
  217. empathy_software_plugin/wizards/security/exploit_analyzer.py +290 -0
  218. empathy_software_plugin/wizards/security/owasp_patterns.py +241 -0
  219. empathy_software_plugin/wizards/security/vulnerability_scanner.py +604 -0
  220. empathy_software_plugin/wizards/security_analysis_wizard.py +322 -0
  221. empathy_software_plugin/wizards/security_learning_wizard.py +740 -0
  222. empathy_software_plugin/wizards/tech_debt_wizard.py +726 -0
  223. empathy_software_plugin/wizards/testing/__init__.py +27 -0
  224. empathy_software_plugin/wizards/testing/coverage_analyzer.py +459 -0
  225. empathy_software_plugin/wizards/testing/quality_analyzer.py +531 -0
  226. empathy_software_plugin/wizards/testing/test_suggester.py +533 -0
  227. empathy_software_plugin/wizards/testing_wizard.py +274 -0
  228. hot_reload/README.md +473 -0
  229. hot_reload/__init__.py +62 -0
  230. hot_reload/config.py +84 -0
  231. hot_reload/integration.py +228 -0
  232. hot_reload/reloader.py +298 -0
  233. hot_reload/watcher.py +179 -0
  234. hot_reload/websocket.py +176 -0
  235. scaffolding/README.md +589 -0
  236. scaffolding/__init__.py +35 -0
  237. scaffolding/__main__.py +14 -0
  238. scaffolding/cli.py +240 -0
  239. test_generator/__init__.py +38 -0
  240. test_generator/__main__.py +14 -0
  241. test_generator/cli.py +226 -0
  242. test_generator/generator.py +325 -0
  243. test_generator/risk_analyzer.py +216 -0
  244. workflow_patterns/__init__.py +33 -0
  245. workflow_patterns/behavior.py +249 -0
  246. workflow_patterns/core.py +76 -0
  247. workflow_patterns/output.py +99 -0
  248. workflow_patterns/registry.py +255 -0
  249. workflow_patterns/structural.py +288 -0
  250. workflow_scaffolding/__init__.py +11 -0
  251. workflow_scaffolding/__main__.py +12 -0
  252. workflow_scaffolding/cli.py +206 -0
  253. workflow_scaffolding/generator.py +265 -0
  254. agents/code_inspection/patterns/inspection/recurring_B112.json +0 -18
  255. agents/code_inspection/patterns/inspection/recurring_F541.json +0 -16
  256. agents/code_inspection/patterns/inspection/recurring_FORMAT.json +0 -25
  257. agents/code_inspection/patterns/inspection/recurring_bug_20250822_def456.json +0 -16
  258. agents/code_inspection/patterns/inspection/recurring_bug_20250915_abc123.json +0 -16
  259. agents/code_inspection/patterns/inspection/recurring_bug_20251212_3c5b9951.json +0 -16
  260. agents/code_inspection/patterns/inspection/recurring_bug_20251212_97c0f72f.json +0 -16
  261. agents/code_inspection/patterns/inspection/recurring_bug_20251212_a0871d53.json +0 -16
  262. agents/code_inspection/patterns/inspection/recurring_bug_20251212_a9b6ec41.json +0 -16
  263. agents/code_inspection/patterns/inspection/recurring_bug_null_001.json +0 -16
  264. agents/code_inspection/patterns/inspection/recurring_builtin.json +0 -16
  265. agents/compliance_anticipation_agent.py +0 -1422
  266. agents/compliance_db.py +0 -339
  267. agents/epic_integration_wizard.py +0 -530
  268. agents/notifications.py +0 -291
  269. agents/trust_building_behaviors.py +0 -872
  270. empathy_framework-3.7.0.dist-info/RECORD +0 -105
  271. {empathy_framework-3.7.0.dist-info → empathy_framework-3.8.0.dist-info}/WHEEL +0 -0
  272. {empathy_framework-3.7.0.dist-info → empathy_framework-3.8.0.dist-info}/entry_points.txt +0 -0
  273. {empathy_framework-3.7.0.dist-info → empathy_framework-3.8.0.dist-info}/licenses/LICENSE +0 -0
  274. /empathy_os/{monitoring.py → agent_monitoring.py} +0 -0
@@ -0,0 +1,214 @@
1
+ """Protocol Loader
2
+
3
+ Loads clinical pathway protocols from JSON files.
4
+
5
+ This is like loading linting configs - protocols define the rules.
6
+
7
+ Copyright 2025 Smart AI Memory, LLC
8
+ Licensed under Fair Source 0.9
9
+ """
10
+
11
+ import json
12
+ from dataclasses import dataclass
13
+ from pathlib import Path
14
+ from typing import Any
15
+
16
+
17
+ @dataclass
18
+ class ProtocolCriterion:
19
+ """A single criterion in a protocol"""
20
+
21
+ parameter: str
22
+ condition: str # "<=", ">=", "==", "!=", "altered", etc.
23
+ value: Any | None = None
24
+ points: int = 0
25
+ description: str | None = None
26
+
27
+
28
+ @dataclass
29
+ class ProtocolIntervention:
30
+ """A required intervention"""
31
+
32
+ order: int
33
+ action: str
34
+ timing: str
35
+ required: bool = True
36
+ parameters: dict[str, Any] | None = None
37
+
38
+
39
+ @dataclass
40
+ class ClinicalProtocol:
41
+ """Clinical pathway protocol.
42
+
43
+ This is the "linting config" for healthcare - defines the rules.
44
+ """
45
+
46
+ name: str
47
+ version: str
48
+ applies_to: list[str]
49
+
50
+ # Screening criteria (when to activate protocol)
51
+ screening_criteria: list[ProtocolCriterion]
52
+ screening_threshold: int
53
+
54
+ # Required interventions (what to do)
55
+ interventions: list[ProtocolIntervention]
56
+
57
+ # Monitoring requirements
58
+ monitoring_frequency: str
59
+ reassessment_timing: str
60
+
61
+ # Escalation criteria (when to call for help)
62
+ escalation_criteria: list[str] | None = None
63
+
64
+ # Documentation requirements
65
+ documentation_requirements: list[str] | None = None
66
+
67
+ # Raw protocol data
68
+ raw_protocol: dict[str, Any] | None = None
69
+
70
+
71
+ class ProtocolLoader:
72
+ """Loads clinical protocols from JSON files.
73
+
74
+ Similar to loading .eslintrc or pyproject.toml - we're loading
75
+ the protocol configuration.
76
+ """
77
+
78
+ def __init__(self, protocol_directory: str | None = None):
79
+ if protocol_directory:
80
+ self.protocol_dir = Path(protocol_directory)
81
+ else:
82
+ # Default to protocols directory in plugin
83
+ plugin_dir = Path(__file__).parent.parent.parent
84
+ self.protocol_dir = plugin_dir / "protocols"
85
+
86
+ def load_protocol(self, protocol_name: str) -> ClinicalProtocol:
87
+ """Load protocol by name.
88
+
89
+ Args:
90
+ protocol_name: Name of protocol (e.g., "sepsis", "post_operative")
91
+
92
+ Returns:
93
+ ClinicalProtocol object
94
+
95
+ Example:
96
+ >>> loader = ProtocolLoader()
97
+ >>> protocol = loader.load_protocol("sepsis")
98
+ >>> print(f"Loaded: {protocol.name} v{protocol.version}")
99
+
100
+ """
101
+ protocol_file = self.protocol_dir / f"{protocol_name}.json"
102
+
103
+ if not protocol_file.exists():
104
+ raise FileNotFoundError(
105
+ f"Protocol not found: {protocol_name}\nLooked in: {self.protocol_dir}",
106
+ )
107
+
108
+ with open(protocol_file) as f:
109
+ data = json.load(f)
110
+
111
+ return self._parse_protocol(data)
112
+
113
+ def _parse_protocol(self, data: dict[str, Any]) -> ClinicalProtocol:
114
+ """Parse protocol JSON into ClinicalProtocol object"""
115
+ # Parse screening criteria
116
+ screening_data = data.get("screening_criteria", {})
117
+ criteria = []
118
+
119
+ for crit in screening_data.get("criteria", []):
120
+ criteria.append(
121
+ ProtocolCriterion(
122
+ parameter=crit["parameter"],
123
+ condition=crit["condition"],
124
+ value=crit.get("value"),
125
+ points=crit.get("points", 0),
126
+ description=crit.get("description"),
127
+ ),
128
+ )
129
+
130
+ # Parse interventions
131
+ interventions = []
132
+ for interv in data.get("interventions", []):
133
+ interventions.append(
134
+ ProtocolIntervention(
135
+ order=interv["order"],
136
+ action=interv["action"],
137
+ timing=interv["timing"],
138
+ required=interv.get("required", True),
139
+ parameters=interv.get("parameters"),
140
+ ),
141
+ )
142
+
143
+ # Parse monitoring requirements
144
+ monitoring = data.get("monitoring_requirements", {})
145
+
146
+ return ClinicalProtocol(
147
+ name=data["protocol_name"],
148
+ version=data["protocol_version"],
149
+ applies_to=data.get("applies_to", []),
150
+ screening_criteria=criteria,
151
+ screening_threshold=screening_data.get("threshold", 0),
152
+ interventions=interventions,
153
+ monitoring_frequency=monitoring.get("vitals_frequency", "hourly"),
154
+ reassessment_timing=monitoring.get("reassessment", "hourly"),
155
+ escalation_criteria=data.get("escalation_criteria", {}).get("if", []),
156
+ documentation_requirements=data.get("documentation_requirements", []),
157
+ raw_protocol=data,
158
+ )
159
+
160
+ def list_available_protocols(self) -> list[str]:
161
+ """List all available protocols"""
162
+ if not self.protocol_dir.exists():
163
+ return []
164
+
165
+ protocols = []
166
+ for file in self.protocol_dir.glob("*.json"):
167
+ protocols.append(file.stem)
168
+
169
+ return sorted(protocols)
170
+
171
+ def validate_protocol(self, protocol: ClinicalProtocol) -> list[str]:
172
+ """Validate protocol structure.
173
+
174
+ Returns list of validation errors (empty if valid)
175
+ """
176
+ errors = []
177
+
178
+ if not protocol.name:
179
+ errors.append("Protocol must have a name")
180
+
181
+ if not protocol.version:
182
+ errors.append("Protocol must have a version")
183
+
184
+ if not protocol.screening_criteria:
185
+ errors.append("Protocol must have screening criteria")
186
+
187
+ if not protocol.interventions:
188
+ errors.append("Protocol must have interventions")
189
+
190
+ # Check intervention order
191
+ orders = [i.order for i in protocol.interventions]
192
+ if len(orders) != len(set(orders)):
193
+ errors.append("Intervention orders must be unique")
194
+
195
+ return errors
196
+
197
+
198
+ def load_protocol(protocol_name: str, protocol_dir: str | None = None) -> ClinicalProtocol:
199
+ """Convenience function to load a protocol.
200
+
201
+ Args:
202
+ protocol_name: Name of protocol
203
+ protocol_dir: Optional custom protocol directory
204
+
205
+ Returns:
206
+ ClinicalProtocol object
207
+
208
+ Example:
209
+ >>> protocol = load_protocol("sepsis")
210
+ >>> print(f"{protocol.name}: {len(protocol.interventions)} interventions")
211
+
212
+ """
213
+ loader = ProtocolLoader(protocol_dir)
214
+ return loader.load_protocol(protocol_name)
@@ -0,0 +1,306 @@
1
+ """Sensor Data Parsers
2
+
3
+ Parses sensor data from various formats (HL7, FHIR, manual entry).
4
+
5
+ This is like parsing linter output - converting various formats to standard structure.
6
+
7
+ Copyright 2025 Smart AI Memory, LLC
8
+ Licensed under Fair Source 0.9
9
+ """
10
+
11
+ import json
12
+ from dataclasses import dataclass
13
+ from datetime import datetime
14
+ from enum import Enum
15
+ from typing import Any
16
+
17
+
18
+ class VitalSignType(Enum):
19
+ """Types of vital signs"""
20
+
21
+ HEART_RATE = "heart_rate"
22
+ BLOOD_PRESSURE = "blood_pressure"
23
+ RESPIRATORY_RATE = "respiratory_rate"
24
+ TEMPERATURE = "temperature"
25
+ OXYGEN_SATURATION = "oxygen_saturation"
26
+ MENTAL_STATUS = "mental_status"
27
+ PAIN_SCORE = "pain_score"
28
+
29
+
30
+ @dataclass
31
+ class VitalSignReading:
32
+ """Standardized vital sign reading.
33
+
34
+ This is the universal format - all parsers convert to this.
35
+ """
36
+
37
+ vital_type: VitalSignType
38
+ value: Any
39
+ unit: str
40
+ timestamp: datetime
41
+ source: str # "bedside_monitor", "manual_entry", "wearable"
42
+ patient_id: str
43
+ quality: str | None = None # "good", "poor", "artifact"
44
+ metadata: dict[str, Any] | None = None
45
+
46
+ def to_dict(self) -> dict[str, Any]:
47
+ """Convert to dictionary"""
48
+ return {
49
+ "vital_type": self.vital_type.value,
50
+ "value": self.value,
51
+ "unit": self.unit,
52
+ "timestamp": self.timestamp.isoformat(),
53
+ "source": self.source,
54
+ "patient_id": self.patient_id,
55
+ "quality": self.quality,
56
+ "metadata": self.metadata or {},
57
+ }
58
+
59
+
60
+ class BaseSensorParser:
61
+ """Base class for sensor data parsers"""
62
+
63
+ def parse(self, data: str) -> list[VitalSignReading]:
64
+ """Parse sensor data into standardized readings"""
65
+ raise NotImplementedError(
66
+ f"{self.__class__.__name__}.parse() must be implemented. "
67
+ "Create a subclass of BaseSensorParser and implement the parse() method. "
68
+ f"See FHIRObservationParser or SimpleJSONParser for examples."
69
+ )
70
+
71
+
72
+ class FHIRObservationParser(BaseSensorParser):
73
+ """Parse FHIR Observation resources.
74
+
75
+ FHIR is standard for healthcare data exchange.
76
+ """
77
+
78
+ # LOINC codes for common vitals
79
+ LOINC_MAPPINGS = {
80
+ "8867-4": VitalSignType.HEART_RATE,
81
+ "8480-6": VitalSignType.BLOOD_PRESSURE, # Systolic
82
+ "8462-4": VitalSignType.BLOOD_PRESSURE, # Diastolic
83
+ "9279-1": VitalSignType.RESPIRATORY_RATE,
84
+ "8310-5": VitalSignType.TEMPERATURE,
85
+ "2708-6": VitalSignType.OXYGEN_SATURATION,
86
+ "38208-5": VitalSignType.PAIN_SCORE,
87
+ }
88
+
89
+ def parse(self, data: str) -> list[VitalSignReading]:
90
+ """Parse FHIR Observation JSON"""
91
+ try:
92
+ observation = json.loads(data)
93
+ except json.JSONDecodeError:
94
+ return []
95
+
96
+ if observation.get("resourceType") != "Observation":
97
+ return []
98
+
99
+ readings = []
100
+
101
+ # Extract LOINC code
102
+ code = observation.get("code", {})
103
+ loinc_code = None
104
+
105
+ for coding in code.get("coding", []):
106
+ if coding.get("system") == "http://loinc.org":
107
+ loinc_code = coding.get("code")
108
+ break
109
+
110
+ if not loinc_code or loinc_code not in self.LOINC_MAPPINGS:
111
+ return []
112
+
113
+ vital_type = self.LOINC_MAPPINGS[loinc_code]
114
+
115
+ # Extract value
116
+ value_qty = observation.get("valueQuantity", {})
117
+ value = value_qty.get("value")
118
+ unit = value_qty.get("unit", "")
119
+
120
+ # Extract timestamp
121
+ timestamp_str = observation.get("effectiveDateTime")
122
+ timestamp = (
123
+ datetime.fromisoformat(timestamp_str.replace("Z", "+00:00"))
124
+ if timestamp_str
125
+ else datetime.now()
126
+ )
127
+
128
+ # Extract patient ID
129
+ subject = observation.get("subject", {})
130
+ patient_id = subject.get("reference", "").split("/")[-1]
131
+
132
+ reading = VitalSignReading(
133
+ vital_type=vital_type,
134
+ value=value,
135
+ unit=unit,
136
+ timestamp=timestamp,
137
+ source="fhir_observation",
138
+ patient_id=patient_id,
139
+ metadata={"loinc_code": loinc_code},
140
+ )
141
+
142
+ readings.append(reading)
143
+
144
+ return readings
145
+
146
+
147
+ class SimpleJSONParser(BaseSensorParser):
148
+ """Parse simple JSON format for manual entry or simulation.
149
+
150
+ Example:
151
+ {
152
+ "patient_id": "12345",
153
+ "timestamp": "2024-01-20T14:30:00Z",
154
+ "vitals": {
155
+ "hr": 110,
156
+ "systolic_bp": 95,
157
+ "diastolic_bp": 60,
158
+ "respiratory_rate": 24,
159
+ "temp_f": 101.5,
160
+ "o2_sat": 94
161
+ }
162
+ }
163
+
164
+ """
165
+
166
+ VITAL_MAPPINGS = {
167
+ "hr": (VitalSignType.HEART_RATE, "bpm"),
168
+ "heart_rate": (VitalSignType.HEART_RATE, "bpm"),
169
+ "systolic_bp": (VitalSignType.BLOOD_PRESSURE, "mmHg"),
170
+ "diastolic_bp": (VitalSignType.BLOOD_PRESSURE, "mmHg"),
171
+ "bp": (VitalSignType.BLOOD_PRESSURE, "mmHg"),
172
+ "respiratory_rate": (VitalSignType.RESPIRATORY_RATE, "/min"),
173
+ "rr": (VitalSignType.RESPIRATORY_RATE, "/min"),
174
+ "temp_f": (VitalSignType.TEMPERATURE, "°F"),
175
+ "temp_c": (VitalSignType.TEMPERATURE, "°C"),
176
+ "temperature": (VitalSignType.TEMPERATURE, "°F"),
177
+ "o2_sat": (VitalSignType.OXYGEN_SATURATION, "%"),
178
+ "spo2": (VitalSignType.OXYGEN_SATURATION, "%"),
179
+ "mental_status": (VitalSignType.MENTAL_STATUS, "text"),
180
+ "pain": (VitalSignType.PAIN_SCORE, "0-10"),
181
+ }
182
+
183
+ def parse(self, data: str) -> list[VitalSignReading]:
184
+ """Parse simple JSON format"""
185
+ try:
186
+ parsed = json.loads(data)
187
+ except json.JSONDecodeError:
188
+ return []
189
+
190
+ patient_id = parsed.get("patient_id", "unknown")
191
+ timestamp_str = parsed.get("timestamp")
192
+ timestamp = (
193
+ datetime.fromisoformat(timestamp_str.replace("Z", "+00:00"))
194
+ if timestamp_str
195
+ else datetime.now()
196
+ )
197
+
198
+ vitals = parsed.get("vitals", {})
199
+
200
+ readings = []
201
+
202
+ for key, value in vitals.items():
203
+ if key in self.VITAL_MAPPINGS:
204
+ vital_type, unit = self.VITAL_MAPPINGS[key]
205
+
206
+ reading = VitalSignReading(
207
+ vital_type=vital_type,
208
+ value=value,
209
+ unit=unit,
210
+ timestamp=timestamp,
211
+ source="manual_entry",
212
+ patient_id=patient_id,
213
+ )
214
+
215
+ readings.append(reading)
216
+
217
+ return readings
218
+
219
+
220
+ class SensorParserFactory:
221
+ """Factory for creating appropriate sensor parser"""
222
+
223
+ _parsers = {"fhir": FHIRObservationParser, "simple_json": SimpleJSONParser}
224
+
225
+ @classmethod
226
+ def create(cls, format_type: str) -> BaseSensorParser:
227
+ """Create parser for specified format"""
228
+ parser_class = cls._parsers.get(format_type)
229
+
230
+ if not parser_class:
231
+ raise ValueError(
232
+ f"Unsupported sensor format: {format_type}. "
233
+ f"Supported: {', '.join(cls._parsers.keys())}",
234
+ )
235
+
236
+ return parser_class()
237
+
238
+
239
+ def parse_sensor_data(data: str, format_type: str = "simple_json") -> list[VitalSignReading]:
240
+ """Convenience function to parse sensor data.
241
+
242
+ Args:
243
+ data: Raw sensor data (JSON string)
244
+ format_type: "fhir" or "simple_json"
245
+
246
+ Returns:
247
+ List of VitalSignReading objects
248
+
249
+ Example:
250
+ >>> data = '{"patient_id": "12345", "vitals": {"hr": 110}}'
251
+ >>> readings = parse_sensor_data(data, "simple_json")
252
+ >>> print(f"HR: {readings[0].value} {readings[0].unit}")
253
+
254
+ """
255
+ parser = SensorParserFactory.create(format_type)
256
+ return parser.parse(data)
257
+
258
+
259
+ def normalize_vitals(readings: list[VitalSignReading]) -> dict[str, Any]:
260
+ """Normalize vital sign readings into protocol-checkable format.
261
+
262
+ Takes list of VitalSignReading and converts to dict for protocol checker.
263
+
264
+ Args:
265
+ readings: List of vital sign readings
266
+
267
+ Returns:
268
+ Dictionary with normalized values for protocol checking
269
+
270
+ Example:
271
+ >>> normalized = normalize_vitals(readings)
272
+ >>> # Returns: {"hr": 110, "systolic_bp": 95, "respiratory_rate": 24}
273
+
274
+ """
275
+ normalized = {}
276
+
277
+ for reading in readings:
278
+ if reading.vital_type == VitalSignType.HEART_RATE:
279
+ normalized["hr"] = reading.value
280
+
281
+ elif reading.vital_type == VitalSignType.BLOOD_PRESSURE:
282
+ # Determine if systolic or diastolic based on value
283
+ if reading.value > 60: # Likely systolic
284
+ normalized["systolic_bp"] = reading.value
285
+ else: # Likely diastolic
286
+ normalized["diastolic_bp"] = reading.value
287
+
288
+ elif reading.vital_type == VitalSignType.RESPIRATORY_RATE:
289
+ normalized["respiratory_rate"] = reading.value
290
+
291
+ elif reading.vital_type == VitalSignType.TEMPERATURE:
292
+ if reading.unit == "°F":
293
+ normalized["temp_f"] = reading.value
294
+ elif reading.unit == "°C":
295
+ normalized["temp_c"] = reading.value
296
+
297
+ elif reading.vital_type == VitalSignType.OXYGEN_SATURATION:
298
+ normalized["o2_sat"] = reading.value
299
+
300
+ elif reading.vital_type == VitalSignType.MENTAL_STATUS:
301
+ normalized["mental_status"] = reading.value
302
+
303
+ elif reading.vital_type == VitalSignType.PAIN_SCORE:
304
+ normalized["pain_score"] = reading.value
305
+
306
+ return normalized