empathy-framework 2.4.0__py3-none-any.whl → 3.8.2__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.
- coach_wizards/__init__.py +13 -12
- coach_wizards/accessibility_wizard.py +12 -12
- coach_wizards/api_wizard.py +12 -12
- coach_wizards/base_wizard.py +26 -20
- coach_wizards/cicd_wizard.py +15 -13
- coach_wizards/code_reviewer_README.md +60 -0
- coach_wizards/code_reviewer_wizard.py +180 -0
- coach_wizards/compliance_wizard.py +12 -12
- coach_wizards/database_wizard.py +12 -12
- coach_wizards/debugging_wizard.py +12 -12
- coach_wizards/documentation_wizard.py +12 -12
- coach_wizards/generate_wizards.py +1 -2
- coach_wizards/localization_wizard.py +101 -19
- coach_wizards/migration_wizard.py +12 -12
- coach_wizards/monitoring_wizard.py +12 -12
- coach_wizards/observability_wizard.py +12 -12
- coach_wizards/performance_wizard.py +12 -12
- coach_wizards/prompt_engineering_wizard.py +661 -0
- coach_wizards/refactoring_wizard.py +12 -12
- coach_wizards/scaling_wizard.py +12 -12
- coach_wizards/security_wizard.py +12 -12
- coach_wizards/testing_wizard.py +12 -12
- empathy_framework-3.8.2.dist-info/METADATA +1176 -0
- empathy_framework-3.8.2.dist-info/RECORD +333 -0
- empathy_framework-3.8.2.dist-info/entry_points.txt +22 -0
- {empathy_framework-2.4.0.dist-info → empathy_framework-3.8.2.dist-info}/top_level.txt +5 -1
- empathy_healthcare_plugin/__init__.py +1 -2
- empathy_healthcare_plugin/monitors/__init__.py +9 -0
- empathy_healthcare_plugin/monitors/clinical_protocol_monitor.py +315 -0
- empathy_healthcare_plugin/monitors/monitoring/__init__.py +44 -0
- empathy_healthcare_plugin/monitors/monitoring/protocol_checker.py +300 -0
- empathy_healthcare_plugin/monitors/monitoring/protocol_loader.py +214 -0
- empathy_healthcare_plugin/monitors/monitoring/sensor_parsers.py +306 -0
- empathy_healthcare_plugin/monitors/monitoring/trajectory_analyzer.py +389 -0
- empathy_llm_toolkit/__init__.py +7 -7
- empathy_llm_toolkit/agent_factory/__init__.py +53 -0
- empathy_llm_toolkit/agent_factory/adapters/__init__.py +85 -0
- empathy_llm_toolkit/agent_factory/adapters/autogen_adapter.py +312 -0
- empathy_llm_toolkit/agent_factory/adapters/crewai_adapter.py +454 -0
- empathy_llm_toolkit/agent_factory/adapters/haystack_adapter.py +298 -0
- empathy_llm_toolkit/agent_factory/adapters/langchain_adapter.py +362 -0
- empathy_llm_toolkit/agent_factory/adapters/langgraph_adapter.py +333 -0
- empathy_llm_toolkit/agent_factory/adapters/native.py +228 -0
- empathy_llm_toolkit/agent_factory/adapters/wizard_adapter.py +426 -0
- empathy_llm_toolkit/agent_factory/base.py +305 -0
- empathy_llm_toolkit/agent_factory/crews/__init__.py +67 -0
- empathy_llm_toolkit/agent_factory/crews/code_review.py +1113 -0
- empathy_llm_toolkit/agent_factory/crews/health_check.py +1246 -0
- empathy_llm_toolkit/agent_factory/crews/refactoring.py +1128 -0
- empathy_llm_toolkit/agent_factory/crews/security_audit.py +1018 -0
- empathy_llm_toolkit/agent_factory/decorators.py +286 -0
- empathy_llm_toolkit/agent_factory/factory.py +558 -0
- empathy_llm_toolkit/agent_factory/framework.py +192 -0
- empathy_llm_toolkit/agent_factory/memory_integration.py +324 -0
- empathy_llm_toolkit/agent_factory/resilient.py +320 -0
- empathy_llm_toolkit/claude_memory.py +14 -15
- empathy_llm_toolkit/cli/__init__.py +8 -0
- empathy_llm_toolkit/cli/sync_claude.py +487 -0
- empathy_llm_toolkit/code_health.py +186 -28
- empathy_llm_toolkit/config/__init__.py +29 -0
- empathy_llm_toolkit/config/unified.py +295 -0
- empathy_llm_toolkit/contextual_patterns.py +11 -12
- empathy_llm_toolkit/core.py +168 -53
- empathy_llm_toolkit/git_pattern_extractor.py +17 -13
- empathy_llm_toolkit/levels.py +6 -13
- empathy_llm_toolkit/pattern_confidence.py +14 -18
- empathy_llm_toolkit/pattern_resolver.py +10 -12
- empathy_llm_toolkit/pattern_summary.py +16 -14
- empathy_llm_toolkit/providers.py +194 -28
- empathy_llm_toolkit/routing/__init__.py +32 -0
- empathy_llm_toolkit/routing/model_router.py +362 -0
- empathy_llm_toolkit/security/IMPLEMENTATION_SUMMARY.md +413 -0
- empathy_llm_toolkit/security/PHASE2_COMPLETE.md +384 -0
- empathy_llm_toolkit/security/PHASE2_SECRETS_DETECTOR_COMPLETE.md +271 -0
- empathy_llm_toolkit/security/QUICK_REFERENCE.md +316 -0
- empathy_llm_toolkit/security/README.md +262 -0
- empathy_llm_toolkit/security/__init__.py +62 -0
- empathy_llm_toolkit/security/audit_logger.py +929 -0
- empathy_llm_toolkit/security/audit_logger_example.py +152 -0
- empathy_llm_toolkit/security/pii_scrubber.py +640 -0
- empathy_llm_toolkit/security/secrets_detector.py +678 -0
- empathy_llm_toolkit/security/secrets_detector_example.py +304 -0
- empathy_llm_toolkit/security/secure_memdocs.py +1192 -0
- empathy_llm_toolkit/security/secure_memdocs_example.py +278 -0
- empathy_llm_toolkit/session_status.py +20 -22
- empathy_llm_toolkit/state.py +28 -21
- empathy_llm_toolkit/wizards/__init__.py +38 -0
- empathy_llm_toolkit/wizards/base_wizard.py +364 -0
- empathy_llm_toolkit/wizards/customer_support_wizard.py +190 -0
- empathy_llm_toolkit/wizards/healthcare_wizard.py +362 -0
- empathy_llm_toolkit/wizards/patient_assessment_README.md +64 -0
- empathy_llm_toolkit/wizards/patient_assessment_wizard.py +193 -0
- empathy_llm_toolkit/wizards/technology_wizard.py +194 -0
- empathy_os/__init__.py +125 -84
- empathy_os/adaptive/__init__.py +13 -0
- empathy_os/adaptive/task_complexity.py +127 -0
- empathy_os/{monitoring.py → agent_monitoring.py} +28 -28
- empathy_os/cache/__init__.py +117 -0
- empathy_os/cache/base.py +166 -0
- empathy_os/cache/dependency_manager.py +253 -0
- empathy_os/cache/hash_only.py +248 -0
- empathy_os/cache/hybrid.py +390 -0
- empathy_os/cache/storage.py +282 -0
- empathy_os/cli.py +1516 -70
- empathy_os/cli_unified.py +597 -0
- empathy_os/config/__init__.py +63 -0
- empathy_os/config/xml_config.py +239 -0
- empathy_os/config.py +95 -37
- empathy_os/coordination.py +72 -68
- empathy_os/core.py +94 -107
- empathy_os/cost_tracker.py +74 -55
- empathy_os/dashboard/__init__.py +15 -0
- empathy_os/dashboard/server.py +743 -0
- empathy_os/discovery.py +17 -14
- empathy_os/emergence.py +21 -22
- empathy_os/exceptions.py +18 -30
- empathy_os/feedback_loops.py +30 -33
- empathy_os/levels.py +32 -35
- empathy_os/leverage_points.py +31 -32
- empathy_os/logging_config.py +19 -16
- empathy_os/memory/__init__.py +195 -0
- empathy_os/memory/claude_memory.py +466 -0
- empathy_os/memory/config.py +224 -0
- empathy_os/memory/control_panel.py +1298 -0
- empathy_os/memory/edges.py +179 -0
- empathy_os/memory/graph.py +567 -0
- empathy_os/memory/long_term.py +1194 -0
- empathy_os/memory/nodes.py +179 -0
- empathy_os/memory/redis_bootstrap.py +540 -0
- empathy_os/memory/security/__init__.py +31 -0
- empathy_os/memory/security/audit_logger.py +930 -0
- empathy_os/memory/security/pii_scrubber.py +640 -0
- empathy_os/memory/security/secrets_detector.py +678 -0
- empathy_os/memory/short_term.py +2119 -0
- empathy_os/memory/storage/__init__.py +15 -0
- empathy_os/memory/summary_index.py +583 -0
- empathy_os/memory/unified.py +619 -0
- empathy_os/metrics/__init__.py +12 -0
- empathy_os/metrics/prompt_metrics.py +190 -0
- empathy_os/models/__init__.py +136 -0
- empathy_os/models/__main__.py +13 -0
- empathy_os/models/cli.py +655 -0
- empathy_os/models/empathy_executor.py +354 -0
- empathy_os/models/executor.py +252 -0
- empathy_os/models/fallback.py +671 -0
- empathy_os/models/provider_config.py +563 -0
- empathy_os/models/registry.py +382 -0
- empathy_os/models/tasks.py +302 -0
- empathy_os/models/telemetry.py +548 -0
- empathy_os/models/token_estimator.py +378 -0
- empathy_os/models/validation.py +274 -0
- empathy_os/monitoring/__init__.py +52 -0
- empathy_os/monitoring/alerts.py +23 -0
- empathy_os/monitoring/alerts_cli.py +268 -0
- empathy_os/monitoring/multi_backend.py +271 -0
- empathy_os/monitoring/otel_backend.py +363 -0
- empathy_os/optimization/__init__.py +19 -0
- empathy_os/optimization/context_optimizer.py +272 -0
- empathy_os/pattern_library.py +30 -29
- empathy_os/persistence.py +35 -37
- empathy_os/platform_utils.py +261 -0
- empathy_os/plugins/__init__.py +28 -0
- empathy_os/plugins/base.py +361 -0
- empathy_os/plugins/registry.py +268 -0
- empathy_os/project_index/__init__.py +30 -0
- empathy_os/project_index/cli.py +335 -0
- empathy_os/project_index/crew_integration.py +430 -0
- empathy_os/project_index/index.py +425 -0
- empathy_os/project_index/models.py +501 -0
- empathy_os/project_index/reports.py +473 -0
- empathy_os/project_index/scanner.py +538 -0
- empathy_os/prompts/__init__.py +61 -0
- empathy_os/prompts/config.py +77 -0
- empathy_os/prompts/context.py +177 -0
- empathy_os/prompts/parser.py +285 -0
- empathy_os/prompts/registry.py +313 -0
- empathy_os/prompts/templates.py +208 -0
- empathy_os/redis_config.py +144 -58
- empathy_os/redis_memory.py +79 -77
- empathy_os/resilience/__init__.py +56 -0
- empathy_os/resilience/circuit_breaker.py +256 -0
- empathy_os/resilience/fallback.py +179 -0
- empathy_os/resilience/health.py +300 -0
- empathy_os/resilience/retry.py +209 -0
- empathy_os/resilience/timeout.py +135 -0
- empathy_os/routing/__init__.py +43 -0
- empathy_os/routing/chain_executor.py +433 -0
- empathy_os/routing/classifier.py +217 -0
- empathy_os/routing/smart_router.py +234 -0
- empathy_os/routing/wizard_registry.py +307 -0
- empathy_os/templates.py +19 -14
- empathy_os/trust/__init__.py +28 -0
- empathy_os/trust/circuit_breaker.py +579 -0
- empathy_os/trust_building.py +67 -58
- empathy_os/validation/__init__.py +19 -0
- empathy_os/validation/xml_validator.py +281 -0
- empathy_os/wizard_factory_cli.py +170 -0
- empathy_os/{workflows.py → workflow_commands.py} +131 -37
- empathy_os/workflows/__init__.py +360 -0
- empathy_os/workflows/base.py +1660 -0
- empathy_os/workflows/bug_predict.py +962 -0
- empathy_os/workflows/code_review.py +960 -0
- empathy_os/workflows/code_review_adapters.py +310 -0
- empathy_os/workflows/code_review_pipeline.py +720 -0
- empathy_os/workflows/config.py +600 -0
- empathy_os/workflows/dependency_check.py +648 -0
- empathy_os/workflows/document_gen.py +1069 -0
- empathy_os/workflows/documentation_orchestrator.py +1205 -0
- empathy_os/workflows/health_check.py +679 -0
- empathy_os/workflows/keyboard_shortcuts/__init__.py +39 -0
- empathy_os/workflows/keyboard_shortcuts/generators.py +386 -0
- empathy_os/workflows/keyboard_shortcuts/parsers.py +414 -0
- empathy_os/workflows/keyboard_shortcuts/prompts.py +295 -0
- empathy_os/workflows/keyboard_shortcuts/schema.py +193 -0
- empathy_os/workflows/keyboard_shortcuts/workflow.py +505 -0
- empathy_os/workflows/manage_documentation.py +804 -0
- empathy_os/workflows/new_sample_workflow1.py +146 -0
- empathy_os/workflows/new_sample_workflow1_README.md +150 -0
- empathy_os/workflows/perf_audit.py +687 -0
- empathy_os/workflows/pr_review.py +748 -0
- empathy_os/workflows/progress.py +445 -0
- empathy_os/workflows/progress_server.py +322 -0
- empathy_os/workflows/refactor_plan.py +693 -0
- empathy_os/workflows/release_prep.py +808 -0
- empathy_os/workflows/research_synthesis.py +404 -0
- empathy_os/workflows/secure_release.py +585 -0
- empathy_os/workflows/security_adapters.py +297 -0
- empathy_os/workflows/security_audit.py +1046 -0
- empathy_os/workflows/step_config.py +234 -0
- empathy_os/workflows/test5.py +125 -0
- empathy_os/workflows/test5_README.md +158 -0
- empathy_os/workflows/test_gen.py +1855 -0
- empathy_os/workflows/test_lifecycle.py +526 -0
- empathy_os/workflows/test_maintenance.py +626 -0
- empathy_os/workflows/test_maintenance_cli.py +590 -0
- empathy_os/workflows/test_maintenance_crew.py +821 -0
- empathy_os/workflows/xml_enhanced_crew.py +285 -0
- empathy_software_plugin/__init__.py +1 -2
- empathy_software_plugin/cli/__init__.py +120 -0
- empathy_software_plugin/cli/inspect.py +362 -0
- empathy_software_plugin/cli.py +49 -27
- empathy_software_plugin/plugin.py +4 -8
- empathy_software_plugin/wizards/__init__.py +42 -0
- empathy_software_plugin/wizards/advanced_debugging_wizard.py +392 -0
- empathy_software_plugin/wizards/agent_orchestration_wizard.py +511 -0
- empathy_software_plugin/wizards/ai_collaboration_wizard.py +503 -0
- empathy_software_plugin/wizards/ai_context_wizard.py +441 -0
- empathy_software_plugin/wizards/ai_documentation_wizard.py +503 -0
- empathy_software_plugin/wizards/base_wizard.py +288 -0
- empathy_software_plugin/wizards/book_chapter_wizard.py +519 -0
- empathy_software_plugin/wizards/code_review_wizard.py +606 -0
- empathy_software_plugin/wizards/debugging/__init__.py +50 -0
- empathy_software_plugin/wizards/debugging/bug_risk_analyzer.py +414 -0
- empathy_software_plugin/wizards/debugging/config_loaders.py +442 -0
- empathy_software_plugin/wizards/debugging/fix_applier.py +469 -0
- empathy_software_plugin/wizards/debugging/language_patterns.py +383 -0
- empathy_software_plugin/wizards/debugging/linter_parsers.py +470 -0
- empathy_software_plugin/wizards/debugging/verification.py +369 -0
- empathy_software_plugin/wizards/enhanced_testing_wizard.py +537 -0
- empathy_software_plugin/wizards/memory_enhanced_debugging_wizard.py +816 -0
- empathy_software_plugin/wizards/multi_model_wizard.py +501 -0
- empathy_software_plugin/wizards/pattern_extraction_wizard.py +422 -0
- empathy_software_plugin/wizards/pattern_retriever_wizard.py +400 -0
- empathy_software_plugin/wizards/performance/__init__.py +9 -0
- empathy_software_plugin/wizards/performance/bottleneck_detector.py +221 -0
- empathy_software_plugin/wizards/performance/profiler_parsers.py +278 -0
- empathy_software_plugin/wizards/performance/trajectory_analyzer.py +429 -0
- empathy_software_plugin/wizards/performance_profiling_wizard.py +305 -0
- empathy_software_plugin/wizards/prompt_engineering_wizard.py +425 -0
- empathy_software_plugin/wizards/rag_pattern_wizard.py +461 -0
- empathy_software_plugin/wizards/security/__init__.py +32 -0
- empathy_software_plugin/wizards/security/exploit_analyzer.py +290 -0
- empathy_software_plugin/wizards/security/owasp_patterns.py +241 -0
- empathy_software_plugin/wizards/security/vulnerability_scanner.py +604 -0
- empathy_software_plugin/wizards/security_analysis_wizard.py +322 -0
- empathy_software_plugin/wizards/security_learning_wizard.py +740 -0
- empathy_software_plugin/wizards/tech_debt_wizard.py +726 -0
- empathy_software_plugin/wizards/testing/__init__.py +27 -0
- empathy_software_plugin/wizards/testing/coverage_analyzer.py +459 -0
- empathy_software_plugin/wizards/testing/quality_analyzer.py +531 -0
- empathy_software_plugin/wizards/testing/test_suggester.py +533 -0
- empathy_software_plugin/wizards/testing_wizard.py +274 -0
- hot_reload/README.md +473 -0
- hot_reload/__init__.py +62 -0
- hot_reload/config.py +84 -0
- hot_reload/integration.py +228 -0
- hot_reload/reloader.py +298 -0
- hot_reload/watcher.py +179 -0
- hot_reload/websocket.py +176 -0
- scaffolding/README.md +589 -0
- scaffolding/__init__.py +35 -0
- scaffolding/__main__.py +14 -0
- scaffolding/cli.py +240 -0
- test_generator/__init__.py +38 -0
- test_generator/__main__.py +14 -0
- test_generator/cli.py +226 -0
- test_generator/generator.py +325 -0
- test_generator/risk_analyzer.py +216 -0
- workflow_patterns/__init__.py +33 -0
- workflow_patterns/behavior.py +249 -0
- workflow_patterns/core.py +76 -0
- workflow_patterns/output.py +99 -0
- workflow_patterns/registry.py +255 -0
- workflow_patterns/structural.py +288 -0
- workflow_scaffolding/__init__.py +11 -0
- workflow_scaffolding/__main__.py +12 -0
- workflow_scaffolding/cli.py +206 -0
- workflow_scaffolding/generator.py +265 -0
- agents/code_inspection/patterns/inspection/recurring_B112.json +0 -18
- agents/code_inspection/patterns/inspection/recurring_F541.json +0 -16
- agents/code_inspection/patterns/inspection/recurring_FORMAT.json +0 -25
- agents/code_inspection/patterns/inspection/recurring_bug_20250822_def456.json +0 -16
- agents/code_inspection/patterns/inspection/recurring_bug_20250915_abc123.json +0 -16
- agents/code_inspection/patterns/inspection/recurring_bug_20251212_3c5b9951.json +0 -16
- agents/code_inspection/patterns/inspection/recurring_bug_20251212_97c0f72f.json +0 -16
- agents/code_inspection/patterns/inspection/recurring_bug_20251212_a0871d53.json +0 -16
- agents/code_inspection/patterns/inspection/recurring_bug_20251212_a9b6ec41.json +0 -16
- agents/code_inspection/patterns/inspection/recurring_bug_null_001.json +0 -16
- agents/code_inspection/patterns/inspection/recurring_builtin.json +0 -16
- agents/compliance_anticipation_agent.py +0 -1427
- agents/epic_integration_wizard.py +0 -541
- agents/trust_building_behaviors.py +0 -891
- empathy_framework-2.4.0.dist-info/METADATA +0 -485
- empathy_framework-2.4.0.dist-info/RECORD +0 -102
- empathy_framework-2.4.0.dist-info/entry_points.txt +0 -6
- empathy_llm_toolkit/htmlcov/status.json +0 -1
- empathy_llm_toolkit/security/htmlcov/status.json +0 -1
- {empathy_framework-2.4.0.dist-info → empathy_framework-3.8.2.dist-info}/WHEEL +0 -0
- {empathy_framework-2.4.0.dist-info → empathy_framework-3.8.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,1427 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Compliance Anticipation Agent - Level 4 Anticipatory Empathy
|
|
3
|
-
|
|
4
|
-
Multi-step LangGraph agent that predicts regulatory audits, identifies compliance
|
|
5
|
-
gaps, and prepares documentation proactively to achieve positive outcomes.
|
|
6
|
-
|
|
7
|
-
Key Features:
|
|
8
|
-
1. Audit Timeline Prediction (90+ days advance notice)
|
|
9
|
-
2. Compliance Assessment (automated gap detection)
|
|
10
|
-
3. Proactive Documentation (auto-generate audit packages)
|
|
11
|
-
4. Stakeholder Notification (actionable alerts)
|
|
12
|
-
5. Continuous Monitoring (track until audit completion)
|
|
13
|
-
|
|
14
|
-
Copyright 2025 Smart AI Memory, LLC
|
|
15
|
-
Licensed under Fair Source 0.9
|
|
16
|
-
"""
|
|
17
|
-
|
|
18
|
-
import logging
|
|
19
|
-
import operator
|
|
20
|
-
from collections.abc import Sequence
|
|
21
|
-
from datetime import datetime, timedelta
|
|
22
|
-
from typing import Annotated, TypedDict
|
|
23
|
-
|
|
24
|
-
from langchain_core.messages import AIMessage, BaseMessage
|
|
25
|
-
from langgraph.graph import END, StateGraph
|
|
26
|
-
|
|
27
|
-
logger = logging.getLogger(__name__)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
# =============================================================================
|
|
31
|
-
# Agent State Management - Level 4 Anticipatory Empathy
|
|
32
|
-
# =============================================================================
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
class ComplianceAgentState(TypedDict):
|
|
36
|
-
"""
|
|
37
|
-
Level 4 Anticipatory Agent State
|
|
38
|
-
|
|
39
|
-
Follows Principle #13: "Agent State as Clinical Flowsheet"
|
|
40
|
-
Every field answers a compliance question with clear audit trail.
|
|
41
|
-
|
|
42
|
-
Design Philosophy:
|
|
43
|
-
- State fields answer specific questions ("When?", "What?", "Who?", "How?")
|
|
44
|
-
- All predictions include confidence scores and methods
|
|
45
|
-
- Comprehensive audit trail for legal compliance
|
|
46
|
-
- Actionable outputs (not just status reports)
|
|
47
|
-
"""
|
|
48
|
-
|
|
49
|
-
# =========================================================================
|
|
50
|
-
# Progress Tracking
|
|
51
|
-
# =========================================================================
|
|
52
|
-
current_step: int # 1-5
|
|
53
|
-
completed_steps: list[int]
|
|
54
|
-
messages: Annotated[Sequence[BaseMessage], operator.add]
|
|
55
|
-
|
|
56
|
-
# =========================================================================
|
|
57
|
-
# Audit Prediction (Step 1) - Answers: "When is next audit?"
|
|
58
|
-
# =========================================================================
|
|
59
|
-
next_audit_date: str # ISO format: "2026-04-15"
|
|
60
|
-
days_until_audit: int
|
|
61
|
-
audit_type: str # "joint_commission", "cms", "state_board", "custom"
|
|
62
|
-
audit_cycle_months: int # Typical cycle length (e.g., 36 for Joint Commission)
|
|
63
|
-
|
|
64
|
-
# Prediction Metadata
|
|
65
|
-
prediction_confidence: float # 0.0-1.0
|
|
66
|
-
prediction_method: str # "historical_cycle", "regulatory_schedule", "manual_entry"
|
|
67
|
-
prediction_generated_at: str # ISO timestamp
|
|
68
|
-
last_audit_date: str # ISO format (basis for prediction)
|
|
69
|
-
|
|
70
|
-
# =========================================================================
|
|
71
|
-
# Anticipation Window (Step 2) - Answers: "Should we act now?"
|
|
72
|
-
# =========================================================================
|
|
73
|
-
anticipation_window_days: int # Optimal range: 60-120 days
|
|
74
|
-
is_within_anticipation_window: bool
|
|
75
|
-
time_to_act: str # "too_early", "early", "timely", "urgent", "too_late"
|
|
76
|
-
|
|
77
|
-
# =========================================================================
|
|
78
|
-
# Compliance Assessment (Step 3) - Answers: "Are we compliant?"
|
|
79
|
-
# =========================================================================
|
|
80
|
-
total_compliance_items: int
|
|
81
|
-
compliant_items: int
|
|
82
|
-
non_compliant_items: int
|
|
83
|
-
compliance_percentage: float # 0.0-100.0
|
|
84
|
-
|
|
85
|
-
# Item-Level Detail
|
|
86
|
-
compliance_categories: list[str] # ["medication_safety", "documentation", "patient_safety"]
|
|
87
|
-
category_scores: dict[str, float] # {"medication_safety": 95.0, "documentation": 88.0}
|
|
88
|
-
|
|
89
|
-
# =========================================================================
|
|
90
|
-
# Gap Identification (Step 3) - Answers: "What needs fixing?"
|
|
91
|
-
# =========================================================================
|
|
92
|
-
compliance_gaps: list[dict] # Detailed gap information
|
|
93
|
-
gap_severity_distribution: dict[str, int] # {"critical": 2, "high": 5, "medium": 10}
|
|
94
|
-
|
|
95
|
-
# Gap Structure:
|
|
96
|
-
# {
|
|
97
|
-
# "gap_id": "gap_001",
|
|
98
|
-
# "category": "medication_safety",
|
|
99
|
-
# "item": "High-risk medication double-checks",
|
|
100
|
-
# "description": "5 high-risk meds without documented double-check",
|
|
101
|
-
# "severity": "critical", # critical, high, medium, low
|
|
102
|
-
# "patient_ids": ["P123", "P456"],
|
|
103
|
-
# "incident_dates": ["2025-01-15", "2025-01-18"],
|
|
104
|
-
# "action_required": "Review incidents, document verification",
|
|
105
|
-
# "estimated_time_to_fix": "50 minutes",
|
|
106
|
-
# "can_fix_retroactively": True,
|
|
107
|
-
# "legal_risk": "high"
|
|
108
|
-
# }
|
|
109
|
-
|
|
110
|
-
# =========================================================================
|
|
111
|
-
# Documentation Preparation (Step 4) - Answers: "What evidence do we have?"
|
|
112
|
-
# =========================================================================
|
|
113
|
-
documentation_prepared: bool
|
|
114
|
-
documentation_url: str # Secure storage location
|
|
115
|
-
documentation_files: list[str] # ["compliance_summary.pdf", "gap_analysis.xlsx"]
|
|
116
|
-
|
|
117
|
-
# Documentation Package Contents:
|
|
118
|
-
documentation_package: dict
|
|
119
|
-
# {
|
|
120
|
-
# "summary_report": {...},
|
|
121
|
-
# "evidence_files": [...],
|
|
122
|
-
# "gap_remediation_plan": {...},
|
|
123
|
-
# "timeline": {...},
|
|
124
|
-
# "audit_readiness_score": 85.5
|
|
125
|
-
# }
|
|
126
|
-
|
|
127
|
-
# =========================================================================
|
|
128
|
-
# Stakeholder Notification (Step 5) - Answers: "Who needs to act?"
|
|
129
|
-
# =========================================================================
|
|
130
|
-
notification_sent: bool
|
|
131
|
-
notification_recipients: list[str] # ["charge_nurse", "nurse_manager", "cno"]
|
|
132
|
-
notification_timestamp: str # ISO timestamp
|
|
133
|
-
|
|
134
|
-
# Action Items (Assigned Work)
|
|
135
|
-
action_items: list[dict]
|
|
136
|
-
# {
|
|
137
|
-
# "action_id": "action_001",
|
|
138
|
-
# "gap_id": "gap_001",
|
|
139
|
-
# "description": "Review 5 incidents, document double-checks",
|
|
140
|
-
# "severity": "critical",
|
|
141
|
-
# "assignee": "charge_nurse",
|
|
142
|
-
# "assignee_email": "charge.nurse@hospital.com",
|
|
143
|
-
# "deadline": "2025-02-15",
|
|
144
|
-
# "estimated_time": "50 minutes",
|
|
145
|
-
# "status": "pending",
|
|
146
|
-
# "created_at": "2025-01-20T10:00:00Z"
|
|
147
|
-
# }
|
|
148
|
-
|
|
149
|
-
# =========================================================================
|
|
150
|
-
# Continuous Monitoring (Step 6) - Answers: "How do we track progress?"
|
|
151
|
-
# =========================================================================
|
|
152
|
-
monitoring_scheduled: bool
|
|
153
|
-
monitoring_frequency: str # "daily", "weekly", "biweekly", "monthly"
|
|
154
|
-
next_check_date: str # ISO format
|
|
155
|
-
monitoring_until_date: str # ISO format (audit date)
|
|
156
|
-
|
|
157
|
-
# =========================================================================
|
|
158
|
-
# Positive Outcome Tracking - Answers: "Are we improving?"
|
|
159
|
-
# =========================================================================
|
|
160
|
-
baseline_compliance_percentage: float # Initial assessment
|
|
161
|
-
current_compliance_percentage: float # After interventions
|
|
162
|
-
compliance_improvement: float # Percentage points improved
|
|
163
|
-
gaps_closed: int
|
|
164
|
-
gaps_remaining: int
|
|
165
|
-
|
|
166
|
-
# Trend Analysis
|
|
167
|
-
compliance_trend: str # "improving", "stable", "declining"
|
|
168
|
-
trend_confidence: float # 0.0-1.0
|
|
169
|
-
|
|
170
|
-
# =========================================================================
|
|
171
|
-
# Error Handling & Audit Trail
|
|
172
|
-
# =========================================================================
|
|
173
|
-
errors: list[str]
|
|
174
|
-
warnings: list[str]
|
|
175
|
-
|
|
176
|
-
# Full Audit Trail
|
|
177
|
-
audit_trail: list[dict]
|
|
178
|
-
# {
|
|
179
|
-
# "timestamp": "2025-01-20T10:00:00Z",
|
|
180
|
-
# "step": "predict_audit",
|
|
181
|
-
# "action": "Generated audit prediction",
|
|
182
|
-
# "details": {...},
|
|
183
|
-
# "user": "system"
|
|
184
|
-
# }
|
|
185
|
-
|
|
186
|
-
# =========================================================================
|
|
187
|
-
# Metadata
|
|
188
|
-
# =========================================================================
|
|
189
|
-
hospital_id: str
|
|
190
|
-
facility_name: str
|
|
191
|
-
agent_version: str
|
|
192
|
-
execution_id: str # Unique ID for this agent run
|
|
193
|
-
created_at: str # ISO timestamp
|
|
194
|
-
last_updated: str # ISO timestamp
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
def create_initial_state(
|
|
198
|
-
hospital_id: str, audit_type: str = "joint_commission"
|
|
199
|
-
) -> ComplianceAgentState:
|
|
200
|
-
"""
|
|
201
|
-
Create initial agent state
|
|
202
|
-
|
|
203
|
-
Args:
|
|
204
|
-
hospital_id: Unique identifier for hospital/facility
|
|
205
|
-
audit_type: Type of audit to anticipate
|
|
206
|
-
|
|
207
|
-
Returns:
|
|
208
|
-
Initialized ComplianceAgentState
|
|
209
|
-
"""
|
|
210
|
-
now = datetime.now()
|
|
211
|
-
execution_id = f"compliance_{now.strftime('%Y%m%d_%H%M%S')}_{hospital_id}"
|
|
212
|
-
|
|
213
|
-
return ComplianceAgentState(
|
|
214
|
-
# Progress
|
|
215
|
-
current_step=1,
|
|
216
|
-
completed_steps=[],
|
|
217
|
-
messages=[],
|
|
218
|
-
# Audit Prediction
|
|
219
|
-
next_audit_date="",
|
|
220
|
-
days_until_audit=0,
|
|
221
|
-
audit_type=audit_type,
|
|
222
|
-
audit_cycle_months=0,
|
|
223
|
-
prediction_confidence=0.0,
|
|
224
|
-
prediction_method="",
|
|
225
|
-
prediction_generated_at="",
|
|
226
|
-
last_audit_date="",
|
|
227
|
-
# Anticipation Window
|
|
228
|
-
anticipation_window_days=0,
|
|
229
|
-
is_within_anticipation_window=False,
|
|
230
|
-
time_to_act="",
|
|
231
|
-
# Compliance Assessment
|
|
232
|
-
total_compliance_items=0,
|
|
233
|
-
compliant_items=0,
|
|
234
|
-
non_compliant_items=0,
|
|
235
|
-
compliance_percentage=0.0,
|
|
236
|
-
compliance_categories=[],
|
|
237
|
-
category_scores={},
|
|
238
|
-
# Gaps
|
|
239
|
-
compliance_gaps=[],
|
|
240
|
-
gap_severity_distribution={},
|
|
241
|
-
# Documentation
|
|
242
|
-
documentation_prepared=False,
|
|
243
|
-
documentation_url="",
|
|
244
|
-
documentation_files=[],
|
|
245
|
-
documentation_package={},
|
|
246
|
-
# Notification
|
|
247
|
-
notification_sent=False,
|
|
248
|
-
notification_recipients=[],
|
|
249
|
-
notification_timestamp="",
|
|
250
|
-
action_items=[],
|
|
251
|
-
# Monitoring
|
|
252
|
-
monitoring_scheduled=False,
|
|
253
|
-
monitoring_frequency="",
|
|
254
|
-
next_check_date="",
|
|
255
|
-
monitoring_until_date="",
|
|
256
|
-
# Positive Outcomes
|
|
257
|
-
baseline_compliance_percentage=0.0,
|
|
258
|
-
current_compliance_percentage=0.0,
|
|
259
|
-
compliance_improvement=0.0,
|
|
260
|
-
gaps_closed=0,
|
|
261
|
-
gaps_remaining=0,
|
|
262
|
-
compliance_trend="",
|
|
263
|
-
trend_confidence=0.0,
|
|
264
|
-
# Error Handling
|
|
265
|
-
errors=[],
|
|
266
|
-
warnings=[],
|
|
267
|
-
audit_trail=[],
|
|
268
|
-
# Metadata
|
|
269
|
-
hospital_id=hospital_id,
|
|
270
|
-
facility_name="",
|
|
271
|
-
agent_version="1.0.0",
|
|
272
|
-
execution_id=execution_id,
|
|
273
|
-
created_at=now.isoformat(),
|
|
274
|
-
last_updated=now.isoformat(),
|
|
275
|
-
)
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
# =============================================================================
|
|
279
|
-
# LangGraph Workflow Definition
|
|
280
|
-
# =============================================================================
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
def create_compliance_agent() -> StateGraph:
|
|
284
|
-
"""
|
|
285
|
-
Create Level 4 Anticipatory Compliance Agent
|
|
286
|
-
|
|
287
|
-
Workflow:
|
|
288
|
-
1. Predict Audit Timeline → When will next audit occur?
|
|
289
|
-
2. Check Anticipation Window → Should we act now?
|
|
290
|
-
3. Assess Compliance → Are we ready?
|
|
291
|
-
4. Identify Gaps → What needs fixing?
|
|
292
|
-
5. Prepare Documentation → What evidence do we have?
|
|
293
|
-
6. Notify Stakeholders → Who needs to act?
|
|
294
|
-
7. Schedule Monitoring → How do we track progress?
|
|
295
|
-
|
|
296
|
-
Level 4 Characteristics:
|
|
297
|
-
- Predictive (acts 60-120 days before audit)
|
|
298
|
-
- Proactive (prepares documentation without being asked)
|
|
299
|
-
- Actionable (assigns specific tasks with deadlines)
|
|
300
|
-
- Transparent (explains reasoning, provides confidence scores)
|
|
301
|
-
"""
|
|
302
|
-
|
|
303
|
-
workflow = StateGraph(ComplianceAgentState)
|
|
304
|
-
|
|
305
|
-
# Step 1: Audit Prediction
|
|
306
|
-
workflow.add_node("predict_audit", predict_next_audit)
|
|
307
|
-
workflow.add_node("check_window", check_anticipation_window)
|
|
308
|
-
|
|
309
|
-
# Step 2-3: Assessment
|
|
310
|
-
workflow.add_node("assess_compliance", assess_current_compliance)
|
|
311
|
-
workflow.add_node("identify_gaps", identify_compliance_gaps)
|
|
312
|
-
|
|
313
|
-
# Step 4: Documentation
|
|
314
|
-
workflow.add_node("prepare_docs", prepare_audit_documentation)
|
|
315
|
-
|
|
316
|
-
# Step 5: Notification
|
|
317
|
-
workflow.add_node("notify", send_anticipatory_notifications)
|
|
318
|
-
|
|
319
|
-
# Step 6: Monitoring
|
|
320
|
-
workflow.add_node("schedule_monitor", schedule_continuous_monitoring)
|
|
321
|
-
|
|
322
|
-
# Define edges
|
|
323
|
-
workflow.set_entry_point("predict_audit")
|
|
324
|
-
|
|
325
|
-
workflow.add_edge("predict_audit", "check_window")
|
|
326
|
-
|
|
327
|
-
# Conditional: Only proceed if within anticipation window
|
|
328
|
-
workflow.add_conditional_edges(
|
|
329
|
-
"check_window",
|
|
330
|
-
should_anticipate,
|
|
331
|
-
{
|
|
332
|
-
"anticipate": "assess_compliance",
|
|
333
|
-
"too_early": END,
|
|
334
|
-
"proceed_anyway": "assess_compliance", # Urgent cases
|
|
335
|
-
},
|
|
336
|
-
)
|
|
337
|
-
|
|
338
|
-
workflow.add_edge("assess_compliance", "identify_gaps")
|
|
339
|
-
workflow.add_edge("identify_gaps", "prepare_docs")
|
|
340
|
-
workflow.add_edge("prepare_docs", "notify")
|
|
341
|
-
workflow.add_edge("notify", "schedule_monitor")
|
|
342
|
-
workflow.add_edge("schedule_monitor", END)
|
|
343
|
-
|
|
344
|
-
return workflow.compile()
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
# =============================================================================
|
|
348
|
-
# Node Implementations
|
|
349
|
-
# =============================================================================
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
def predict_next_audit(state: ComplianceAgentState) -> ComplianceAgentState:
|
|
353
|
-
"""
|
|
354
|
-
Step 1: Predict when next audit will occur
|
|
355
|
-
|
|
356
|
-
Methods (in order of preference):
|
|
357
|
-
1. Regulatory schedule (published audit windows) - confidence: 0.95
|
|
358
|
-
2. Historical cycle analysis (e.g., Joint Commission every 36 months) - confidence: 0.85
|
|
359
|
-
3. Risk-based prediction (hospitals with violations audited more) - confidence: 0.70
|
|
360
|
-
4. Manual entry (user provides expected date) - confidence: 0.90
|
|
361
|
-
|
|
362
|
-
For positive outcomes:
|
|
363
|
-
- Early prediction enables proactive preparation
|
|
364
|
-
- Reduces stress and scrambling
|
|
365
|
-
- Allows time to fix gaps without pressure
|
|
366
|
-
"""
|
|
367
|
-
|
|
368
|
-
logger.info(f"[Step 1] Predicting {state['audit_type']} audit for {state['hospital_id']}")
|
|
369
|
-
|
|
370
|
-
# Add to audit trail
|
|
371
|
-
state["audit_trail"].append(
|
|
372
|
-
{
|
|
373
|
-
"timestamp": datetime.now().isoformat(),
|
|
374
|
-
"step": "predict_audit",
|
|
375
|
-
"action": "Starting audit prediction",
|
|
376
|
-
"details": {"audit_type": state["audit_type"]},
|
|
377
|
-
"user": "system",
|
|
378
|
-
}
|
|
379
|
-
)
|
|
380
|
-
|
|
381
|
-
# Get audit cycle for this type
|
|
382
|
-
audit_cycles = {
|
|
383
|
-
"joint_commission": 36, # months
|
|
384
|
-
"cms": 12,
|
|
385
|
-
"state_board": 24,
|
|
386
|
-
"custom": 36,
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
cycle_months = audit_cycles.get(state["audit_type"], 36)
|
|
390
|
-
state["audit_cycle_months"] = cycle_months
|
|
391
|
-
|
|
392
|
-
# TODO: Connect to real database to get last audit date
|
|
393
|
-
# For now, simulate with example date
|
|
394
|
-
# last_audit = get_last_audit_date(state["hospital_id"], state["audit_type"])
|
|
395
|
-
|
|
396
|
-
# Example: Last Joint Commission audit was 2023-04-15
|
|
397
|
-
last_audit = datetime(2023, 4, 15)
|
|
398
|
-
state["last_audit_date"] = last_audit.isoformat()
|
|
399
|
-
|
|
400
|
-
# Predict next audit (add cycle duration)
|
|
401
|
-
predicted_date = last_audit + timedelta(days=cycle_months * 30)
|
|
402
|
-
|
|
403
|
-
# Calculate days until
|
|
404
|
-
days_until = (predicted_date - datetime.now()).days
|
|
405
|
-
|
|
406
|
-
# Confidence based on audit type and data quality
|
|
407
|
-
if state["audit_type"] == "joint_commission":
|
|
408
|
-
confidence = 0.90 # High confidence - very regular cycle
|
|
409
|
-
elif state["audit_type"] == "cms":
|
|
410
|
-
confidence = 0.85 # Good confidence
|
|
411
|
-
else:
|
|
412
|
-
confidence = 0.75 # Moderate confidence
|
|
413
|
-
|
|
414
|
-
# Update state
|
|
415
|
-
state["next_audit_date"] = predicted_date.isoformat()
|
|
416
|
-
state["days_until_audit"] = days_until
|
|
417
|
-
state["prediction_confidence"] = confidence
|
|
418
|
-
state["prediction_method"] = "historical_cycle"
|
|
419
|
-
state["prediction_generated_at"] = datetime.now().isoformat()
|
|
420
|
-
state["last_updated"] = datetime.now().isoformat()
|
|
421
|
-
|
|
422
|
-
# Mark step complete
|
|
423
|
-
state["completed_steps"].append(1)
|
|
424
|
-
state["current_step"] = 2
|
|
425
|
-
|
|
426
|
-
# Log prediction
|
|
427
|
-
logger.info(
|
|
428
|
-
f"Predicted audit: {predicted_date.strftime('%Y-%m-%d')} "
|
|
429
|
-
f"({days_until} days away, {confidence:.0%} confidence)"
|
|
430
|
-
)
|
|
431
|
-
|
|
432
|
-
# Add message
|
|
433
|
-
state["messages"].append(
|
|
434
|
-
AIMessage(
|
|
435
|
-
content=f"Predicted {state['audit_type']} audit on {predicted_date.strftime('%Y-%m-%d')} "
|
|
436
|
-
f"(in {days_until} days) with {confidence:.0%} confidence"
|
|
437
|
-
)
|
|
438
|
-
)
|
|
439
|
-
|
|
440
|
-
# Audit trail
|
|
441
|
-
state["audit_trail"].append(
|
|
442
|
-
{
|
|
443
|
-
"timestamp": datetime.now().isoformat(),
|
|
444
|
-
"step": "predict_audit",
|
|
445
|
-
"action": "Prediction completed",
|
|
446
|
-
"details": {
|
|
447
|
-
"predicted_date": state["next_audit_date"],
|
|
448
|
-
"days_until": days_until,
|
|
449
|
-
"confidence": confidence,
|
|
450
|
-
"method": "historical_cycle",
|
|
451
|
-
},
|
|
452
|
-
"user": "system",
|
|
453
|
-
}
|
|
454
|
-
)
|
|
455
|
-
|
|
456
|
-
return state
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
def check_anticipation_window(state: ComplianceAgentState) -> ComplianceAgentState:
|
|
460
|
-
"""
|
|
461
|
-
Step 2: Check if we're within optimal anticipation window
|
|
462
|
-
|
|
463
|
-
Level 4 Guardrail:
|
|
464
|
-
- Too early (>120 days): Preparation may become outdated, waste effort
|
|
465
|
-
- Optimal (60-120 days): Ideal time for preparation without pressure
|
|
466
|
-
- Urgent (30-60 days): Still helpful but less time to fix issues
|
|
467
|
-
- Too late (<30 days): Limited time for comprehensive fixes
|
|
468
|
-
|
|
469
|
-
For positive outcomes:
|
|
470
|
-
- Acting at right time maximizes effectiveness
|
|
471
|
-
- Avoids wasted effort (too early) or crisis mode (too late)
|
|
472
|
-
"""
|
|
473
|
-
|
|
474
|
-
logger.info(f"[Step 2] Checking anticipation window ({state['days_until_audit']} days)")
|
|
475
|
-
|
|
476
|
-
days_until = state["days_until_audit"]
|
|
477
|
-
|
|
478
|
-
if 60 <= days_until <= 120:
|
|
479
|
-
state["is_within_anticipation_window"] = True
|
|
480
|
-
state["time_to_act"] = "timely"
|
|
481
|
-
state["anticipation_window_days"] = days_until
|
|
482
|
-
message = (
|
|
483
|
-
f"✅ Within optimal anticipation window ({days_until} days). Perfect time to prepare."
|
|
484
|
-
)
|
|
485
|
-
|
|
486
|
-
elif days_until > 120:
|
|
487
|
-
state["is_within_anticipation_window"] = False
|
|
488
|
-
state["time_to_act"] = "too_early"
|
|
489
|
-
state["anticipation_window_days"] = days_until
|
|
490
|
-
message = f"⏰ Audit is {days_until} days away. Will re-check at 120 days out."
|
|
491
|
-
state["warnings"].append(
|
|
492
|
-
f"Audit predicted in {days_until} days. "
|
|
493
|
-
f"Optimal anticipation window is 60-120 days. "
|
|
494
|
-
f"Will schedule re-check for {(datetime.now() + timedelta(days=days_until - 120)).strftime('%Y-%m-%d')}"
|
|
495
|
-
)
|
|
496
|
-
|
|
497
|
-
elif 30 <= days_until < 60:
|
|
498
|
-
state["is_within_anticipation_window"] = True
|
|
499
|
-
state["time_to_act"] = "urgent"
|
|
500
|
-
state["anticipation_window_days"] = days_until
|
|
501
|
-
message = f"⚠️ Only {days_until} days until audit. Acting now (ideally would have started at 90 days)."
|
|
502
|
-
state["warnings"].append(
|
|
503
|
-
"Less than 60 days until audit. "
|
|
504
|
-
"Limited time for comprehensive remediation. "
|
|
505
|
-
"Recommend expedited action."
|
|
506
|
-
)
|
|
507
|
-
|
|
508
|
-
else: # < 30 days
|
|
509
|
-
state["is_within_anticipation_window"] = True
|
|
510
|
-
state["time_to_act"] = "too_late"
|
|
511
|
-
state["anticipation_window_days"] = days_until
|
|
512
|
-
message = f"🚨 URGENT: Only {days_until} days until audit. Focus on critical gaps only."
|
|
513
|
-
state["warnings"].append(
|
|
514
|
-
"Less than 30 days until audit. "
|
|
515
|
-
"Very limited time. Focus on critical compliance gaps only."
|
|
516
|
-
)
|
|
517
|
-
|
|
518
|
-
state["messages"].append(AIMessage(content=message))
|
|
519
|
-
state["completed_steps"].append(2)
|
|
520
|
-
state["current_step"] = 3
|
|
521
|
-
state["last_updated"] = datetime.now().isoformat()
|
|
522
|
-
|
|
523
|
-
# Audit trail
|
|
524
|
-
state["audit_trail"].append(
|
|
525
|
-
{
|
|
526
|
-
"timestamp": datetime.now().isoformat(),
|
|
527
|
-
"step": "check_window",
|
|
528
|
-
"action": "Anticipation window assessed",
|
|
529
|
-
"details": {
|
|
530
|
-
"days_until": days_until,
|
|
531
|
-
"time_to_act": state["time_to_act"],
|
|
532
|
-
"within_window": state["is_within_anticipation_window"],
|
|
533
|
-
},
|
|
534
|
-
"user": "system",
|
|
535
|
-
}
|
|
536
|
-
)
|
|
537
|
-
|
|
538
|
-
logger.info(f"Anticipation window: {state['time_to_act']}")
|
|
539
|
-
|
|
540
|
-
return state
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
def should_anticipate(state: ComplianceAgentState) -> str:
|
|
544
|
-
"""
|
|
545
|
-
Routing function: Decide whether to proceed with anticipation
|
|
546
|
-
|
|
547
|
-
Returns:
|
|
548
|
-
"anticipate" - Within optimal window, proceed
|
|
549
|
-
"too_early" - Too far out, schedule for later
|
|
550
|
-
"proceed_anyway" - Urgent, proceed despite non-optimal timing
|
|
551
|
-
"""
|
|
552
|
-
|
|
553
|
-
time_to_act = state["time_to_act"]
|
|
554
|
-
|
|
555
|
-
if time_to_act == "too_early":
|
|
556
|
-
return "too_early"
|
|
557
|
-
elif time_to_act in ["urgent", "too_late"]:
|
|
558
|
-
return "proceed_anyway"
|
|
559
|
-
else:
|
|
560
|
-
return "anticipate"
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
def assess_current_compliance(state: ComplianceAgentState) -> ComplianceAgentState:
|
|
564
|
-
"""
|
|
565
|
-
Step 3A: Assess current compliance status
|
|
566
|
-
|
|
567
|
-
Scans all compliance requirements for the audit type and determines
|
|
568
|
-
current compliance percentage.
|
|
569
|
-
|
|
570
|
-
For positive outcomes:
|
|
571
|
-
- Comprehensive assessment identifies all issues upfront
|
|
572
|
-
- Categorization helps prioritize remediation
|
|
573
|
-
- Baseline measurement enables tracking improvement
|
|
574
|
-
"""
|
|
575
|
-
|
|
576
|
-
logger.info(f"[Step 3A] Assessing compliance for {state['audit_type']}")
|
|
577
|
-
|
|
578
|
-
# TODO: Connect to real compliance data
|
|
579
|
-
# For now, simulate assessment
|
|
580
|
-
|
|
581
|
-
# Get requirements for this audit type
|
|
582
|
-
requirements = get_audit_requirements(state["audit_type"])
|
|
583
|
-
|
|
584
|
-
# Example: Joint Commission has ~50 compliance items
|
|
585
|
-
total_items = len(requirements)
|
|
586
|
-
|
|
587
|
-
# Simulate compliance check
|
|
588
|
-
# In production, this would scan actual documentation, EHR data, etc.
|
|
589
|
-
compliant = 0
|
|
590
|
-
non_compliant = 0
|
|
591
|
-
category_scores = {}
|
|
592
|
-
|
|
593
|
-
for req in requirements:
|
|
594
|
-
# TODO: Check actual compliance
|
|
595
|
-
# is_compliant = check_requirement_compliance(state["hospital_id"], req)
|
|
596
|
-
|
|
597
|
-
# Simulated: 90% compliant
|
|
598
|
-
import random
|
|
599
|
-
|
|
600
|
-
is_compliant = random.random() < 0.90
|
|
601
|
-
|
|
602
|
-
if is_compliant:
|
|
603
|
-
compliant += 1
|
|
604
|
-
else:
|
|
605
|
-
non_compliant += 1
|
|
606
|
-
|
|
607
|
-
# Track by category
|
|
608
|
-
category = req["category"]
|
|
609
|
-
if category not in category_scores:
|
|
610
|
-
category_scores[category] = {"compliant": 0, "total": 0}
|
|
611
|
-
|
|
612
|
-
category_scores[category]["total"] += 1
|
|
613
|
-
if is_compliant:
|
|
614
|
-
category_scores[category]["compliant"] += 1
|
|
615
|
-
|
|
616
|
-
# Calculate percentages
|
|
617
|
-
compliance_pct = (compliant / total_items * 100) if total_items > 0 else 0.0
|
|
618
|
-
|
|
619
|
-
category_pct = {}
|
|
620
|
-
for cat, scores in category_scores.items():
|
|
621
|
-
category_pct[cat] = (
|
|
622
|
-
(scores["compliant"] / scores["total"] * 100) if scores["total"] > 0 else 0.0
|
|
623
|
-
)
|
|
624
|
-
|
|
625
|
-
# Update state
|
|
626
|
-
state["total_compliance_items"] = total_items
|
|
627
|
-
state["compliant_items"] = compliant
|
|
628
|
-
state["non_compliant_items"] = non_compliant
|
|
629
|
-
state["compliance_percentage"] = compliance_pct
|
|
630
|
-
state["compliance_categories"] = list(category_pct.keys())
|
|
631
|
-
state["category_scores"] = category_pct
|
|
632
|
-
|
|
633
|
-
# Set baseline if first assessment
|
|
634
|
-
if state["baseline_compliance_percentage"] == 0.0:
|
|
635
|
-
state["baseline_compliance_percentage"] = compliance_pct
|
|
636
|
-
|
|
637
|
-
state["current_compliance_percentage"] = compliance_pct
|
|
638
|
-
|
|
639
|
-
state["completed_steps"].append(3)
|
|
640
|
-
state["current_step"] = 4
|
|
641
|
-
state["last_updated"] = datetime.now().isoformat()
|
|
642
|
-
|
|
643
|
-
# Message
|
|
644
|
-
status_emoji = "✅" if compliance_pct >= 95 else "⚠️" if compliance_pct >= 85 else "🚨"
|
|
645
|
-
state["messages"].append(
|
|
646
|
-
AIMessage(
|
|
647
|
-
content=f"{status_emoji} Compliance Assessment: {compliance_pct:.1f}% "
|
|
648
|
-
f"({compliant}/{total_items} items compliant)"
|
|
649
|
-
)
|
|
650
|
-
)
|
|
651
|
-
|
|
652
|
-
# Audit trail
|
|
653
|
-
state["audit_trail"].append(
|
|
654
|
-
{
|
|
655
|
-
"timestamp": datetime.now().isoformat(),
|
|
656
|
-
"step": "assess_compliance",
|
|
657
|
-
"action": "Compliance assessed",
|
|
658
|
-
"details": {
|
|
659
|
-
"total_items": total_items,
|
|
660
|
-
"compliant": compliant,
|
|
661
|
-
"percentage": compliance_pct,
|
|
662
|
-
"categories": category_pct,
|
|
663
|
-
},
|
|
664
|
-
"user": "system",
|
|
665
|
-
}
|
|
666
|
-
)
|
|
667
|
-
|
|
668
|
-
logger.info(f"Compliance: {compliance_pct:.1f}% ({compliant}/{total_items})")
|
|
669
|
-
|
|
670
|
-
return state
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
def identify_compliance_gaps(state: ComplianceAgentState) -> ComplianceAgentState:
|
|
674
|
-
"""
|
|
675
|
-
Step 3B: Identify specific compliance gaps with actionable details
|
|
676
|
-
|
|
677
|
-
For positive outcomes:
|
|
678
|
-
- Specific patient IDs enable targeted remediation
|
|
679
|
-
- Severity classification enables prioritization
|
|
680
|
-
- Time estimates enable resource planning
|
|
681
|
-
- Retroactive fix capability determines urgency
|
|
682
|
-
"""
|
|
683
|
-
|
|
684
|
-
logger.info("[Step 3B] Identifying compliance gaps")
|
|
685
|
-
|
|
686
|
-
# TODO: Connect to real gap detection system
|
|
687
|
-
# For now, simulate common gaps
|
|
688
|
-
|
|
689
|
-
gaps = []
|
|
690
|
-
gap_id_counter = 1
|
|
691
|
-
|
|
692
|
-
# Gap 1: Missing signatures (example)
|
|
693
|
-
if state["compliance_percentage"] < 100:
|
|
694
|
-
gaps.append(
|
|
695
|
-
{
|
|
696
|
-
"gap_id": f"gap_{gap_id_counter:03d}",
|
|
697
|
-
"category": "documentation_completeness",
|
|
698
|
-
"item": "Patient assessment signatures",
|
|
699
|
-
"description": "5 patient assessments missing nurse signatures",
|
|
700
|
-
"severity": "high",
|
|
701
|
-
"patient_ids": ["P12345", "P12367", "P12389", "P12401", "P12423"],
|
|
702
|
-
"incident_dates": [
|
|
703
|
-
"2025-01-15",
|
|
704
|
-
"2025-01-16",
|
|
705
|
-
"2025-01-18",
|
|
706
|
-
"2025-01-19",
|
|
707
|
-
"2025-01-20",
|
|
708
|
-
],
|
|
709
|
-
"action_required": "Nurses must review and sign assessments retroactively",
|
|
710
|
-
"estimated_time_to_fix": "25 minutes",
|
|
711
|
-
"can_fix_retroactively": True,
|
|
712
|
-
"legal_risk": "medium",
|
|
713
|
-
}
|
|
714
|
-
)
|
|
715
|
-
gap_id_counter += 1
|
|
716
|
-
|
|
717
|
-
# Gap 2: Medication double-checks
|
|
718
|
-
if state["compliance_percentage"] < 98:
|
|
719
|
-
gaps.append(
|
|
720
|
-
{
|
|
721
|
-
"gap_id": f"gap_{gap_id_counter:03d}",
|
|
722
|
-
"category": "medication_safety",
|
|
723
|
-
"item": "High-risk medication double-checks",
|
|
724
|
-
"description": "2 high-risk medications administered without documented double-check",
|
|
725
|
-
"severity": "critical",
|
|
726
|
-
"patient_ids": ["P12350", "P12375"],
|
|
727
|
-
"incident_dates": ["2025-01-17", "2025-01-19"],
|
|
728
|
-
"action_required": "Review incidents, document verification process, implement reminder system",
|
|
729
|
-
"estimated_time_to_fix": "45 minutes",
|
|
730
|
-
"can_fix_retroactively": False, # Can document review but can't undo administration
|
|
731
|
-
"legal_risk": "high",
|
|
732
|
-
}
|
|
733
|
-
)
|
|
734
|
-
gap_id_counter += 1
|
|
735
|
-
|
|
736
|
-
# Gap 3: Restraint orders
|
|
737
|
-
if state["compliance_percentage"] < 95:
|
|
738
|
-
gaps.append(
|
|
739
|
-
{
|
|
740
|
-
"gap_id": f"gap_{gap_id_counter:03d}",
|
|
741
|
-
"category": "patient_safety",
|
|
742
|
-
"item": "Restraint order renewals",
|
|
743
|
-
"description": "1 restraint order requires renewal",
|
|
744
|
-
"severity": "high",
|
|
745
|
-
"patient_ids": ["P12390"],
|
|
746
|
-
"incident_dates": ["2025-01-18"],
|
|
747
|
-
"action_required": "Provider must review and renew order immediately",
|
|
748
|
-
"estimated_time_to_fix": "15 minutes",
|
|
749
|
-
"can_fix_retroactively": False,
|
|
750
|
-
"legal_risk": "high",
|
|
751
|
-
}
|
|
752
|
-
)
|
|
753
|
-
gap_id_counter += 1
|
|
754
|
-
|
|
755
|
-
# Calculate severity distribution
|
|
756
|
-
severity_dist = {
|
|
757
|
-
"critical": sum(1 for g in gaps if g["severity"] == "critical"),
|
|
758
|
-
"high": sum(1 for g in gaps if g["severity"] == "high"),
|
|
759
|
-
"medium": sum(1 for g in gaps if g["severity"] == "medium"),
|
|
760
|
-
"low": sum(1 for g in gaps if g["severity"] == "low"),
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
state["compliance_gaps"] = gaps
|
|
764
|
-
state["gap_severity_distribution"] = severity_dist
|
|
765
|
-
state["gaps_remaining"] = len(gaps)
|
|
766
|
-
state["last_updated"] = datetime.now().isoformat()
|
|
767
|
-
|
|
768
|
-
# Message
|
|
769
|
-
if len(gaps) == 0:
|
|
770
|
-
state["messages"].append(
|
|
771
|
-
AIMessage(content="🎉 No compliance gaps identified. Excellent work!")
|
|
772
|
-
)
|
|
773
|
-
else:
|
|
774
|
-
state["messages"].append(
|
|
775
|
-
AIMessage(
|
|
776
|
-
content=f"⚠️ Identified {len(gaps)} compliance gaps: "
|
|
777
|
-
f"{severity_dist['critical']} critical, "
|
|
778
|
-
f"{severity_dist['high']} high, "
|
|
779
|
-
f"{severity_dist['medium']} medium, "
|
|
780
|
-
f"{severity_dist['low']} low"
|
|
781
|
-
)
|
|
782
|
-
)
|
|
783
|
-
|
|
784
|
-
# Audit trail
|
|
785
|
-
state["audit_trail"].append(
|
|
786
|
-
{
|
|
787
|
-
"timestamp": datetime.now().isoformat(),
|
|
788
|
-
"step": "identify_gaps",
|
|
789
|
-
"action": "Gaps identified",
|
|
790
|
-
"details": {
|
|
791
|
-
"gap_count": len(gaps),
|
|
792
|
-
"severity_distribution": severity_dist,
|
|
793
|
-
"gaps": [{"id": g["gap_id"], "description": g["description"]} for g in gaps],
|
|
794
|
-
},
|
|
795
|
-
"user": "system",
|
|
796
|
-
}
|
|
797
|
-
)
|
|
798
|
-
|
|
799
|
-
logger.info(f"Identified {len(gaps)} gaps: {severity_dist}")
|
|
800
|
-
|
|
801
|
-
return state
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
def prepare_audit_documentation(state: ComplianceAgentState) -> ComplianceAgentState:
|
|
805
|
-
"""
|
|
806
|
-
Step 4: Prepare comprehensive audit documentation package
|
|
807
|
-
|
|
808
|
-
For positive outcomes:
|
|
809
|
-
- Pre-prepared documentation reduces audit day stress
|
|
810
|
-
- Structured format ensures completeness
|
|
811
|
-
- Gap remediation plan demonstrates proactive approach
|
|
812
|
-
- Audit readiness score provides confidence metric
|
|
813
|
-
"""
|
|
814
|
-
|
|
815
|
-
logger.info("[Step 4] Preparing audit documentation")
|
|
816
|
-
|
|
817
|
-
# Generate documentation package
|
|
818
|
-
doc_package = {
|
|
819
|
-
"generated_at": datetime.now().isoformat(),
|
|
820
|
-
"audit_type": state["audit_type"],
|
|
821
|
-
"audit_date": state["next_audit_date"],
|
|
822
|
-
"facility": state["hospital_id"],
|
|
823
|
-
"summary_report": {
|
|
824
|
-
"compliance_percentage": state["compliance_percentage"],
|
|
825
|
-
"compliant_items": state["compliant_items"],
|
|
826
|
-
"total_items": state["total_compliance_items"],
|
|
827
|
-
"gap_count": len(state["compliance_gaps"]),
|
|
828
|
-
"severity_breakdown": state["gap_severity_distribution"],
|
|
829
|
-
"category_scores": state["category_scores"],
|
|
830
|
-
},
|
|
831
|
-
"evidence_files": [
|
|
832
|
-
f"medication_administration_records_{state['hospital_id']}.pdf",
|
|
833
|
-
f"patient_assessment_documentation_{state['hospital_id']}.pdf",
|
|
834
|
-
f"infection_control_protocols_{state['hospital_id']}.pdf",
|
|
835
|
-
f"emergency_equipment_checks_{state['hospital_id']}.pdf",
|
|
836
|
-
],
|
|
837
|
-
"gap_remediation_plan": {
|
|
838
|
-
"gaps": state["compliance_gaps"],
|
|
839
|
-
"prioritization": "Critical → High → Medium → Low",
|
|
840
|
-
"estimated_total_time": sum(
|
|
841
|
-
int(g["estimated_time_to_fix"].split()[0])
|
|
842
|
-
for g in state["compliance_gaps"]
|
|
843
|
-
if g["estimated_time_to_fix"].split()[0].isdigit()
|
|
844
|
-
),
|
|
845
|
-
"target_completion_date": (
|
|
846
|
-
datetime.fromisoformat(state["next_audit_date"]) - timedelta(days=14)
|
|
847
|
-
).isoformat(), # 2 weeks before audit
|
|
848
|
-
},
|
|
849
|
-
"timeline": {
|
|
850
|
-
"baseline_assessment": state["created_at"],
|
|
851
|
-
"gap_identification": datetime.now().isoformat(),
|
|
852
|
-
"target_remediation_completion": (
|
|
853
|
-
datetime.fromisoformat(state["next_audit_date"]) - timedelta(days=14)
|
|
854
|
-
).isoformat(),
|
|
855
|
-
"final_verification": (
|
|
856
|
-
datetime.fromisoformat(state["next_audit_date"]) - timedelta(days=7)
|
|
857
|
-
).isoformat(),
|
|
858
|
-
"audit_date": state["next_audit_date"],
|
|
859
|
-
},
|
|
860
|
-
"audit_readiness_score": calculate_audit_readiness_score(state),
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
# Simulate storing documentation
|
|
864
|
-
# TODO: Integrate with actual secure document storage (S3, SharePoint, etc.)
|
|
865
|
-
doc_url = f"https://secure-docs.hospital.com/compliance/{state['execution_id']}"
|
|
866
|
-
doc_files = [
|
|
867
|
-
"compliance_summary_report.pdf",
|
|
868
|
-
"gap_analysis_detailed.xlsx",
|
|
869
|
-
"remediation_plan.pdf",
|
|
870
|
-
"evidence_package.zip",
|
|
871
|
-
]
|
|
872
|
-
|
|
873
|
-
state["documentation_prepared"] = True
|
|
874
|
-
state["documentation_url"] = doc_url
|
|
875
|
-
state["documentation_files"] = doc_files
|
|
876
|
-
state["documentation_package"] = doc_package
|
|
877
|
-
state["last_updated"] = datetime.now().isoformat()
|
|
878
|
-
|
|
879
|
-
# Message
|
|
880
|
-
state["messages"].append(
|
|
881
|
-
AIMessage(
|
|
882
|
-
content=f"📄 Documentation package prepared: {len(doc_files)} files ready at {doc_url}"
|
|
883
|
-
)
|
|
884
|
-
)
|
|
885
|
-
|
|
886
|
-
# Audit trail
|
|
887
|
-
state["audit_trail"].append(
|
|
888
|
-
{
|
|
889
|
-
"timestamp": datetime.now().isoformat(),
|
|
890
|
-
"step": "prepare_docs",
|
|
891
|
-
"action": "Documentation prepared",
|
|
892
|
-
"details": {
|
|
893
|
-
"file_count": len(doc_files),
|
|
894
|
-
"url": doc_url,
|
|
895
|
-
"readiness_score": doc_package["audit_readiness_score"],
|
|
896
|
-
},
|
|
897
|
-
"user": "system",
|
|
898
|
-
}
|
|
899
|
-
)
|
|
900
|
-
|
|
901
|
-
logger.info(f"Documentation prepared: {doc_url}")
|
|
902
|
-
|
|
903
|
-
return state
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
def send_anticipatory_notifications(
|
|
907
|
-
state: ComplianceAgentState,
|
|
908
|
-
) -> ComplianceAgentState:
|
|
909
|
-
"""
|
|
910
|
-
Step 5: Send notifications to stakeholders with actionable information
|
|
911
|
-
|
|
912
|
-
For positive outcomes:
|
|
913
|
-
- Early notification enables calm, planned response
|
|
914
|
-
- Specific assignments clarify responsibilities
|
|
915
|
-
- Deadlines provide urgency without panic
|
|
916
|
-
- Transparent reasoning builds trust in AI system
|
|
917
|
-
"""
|
|
918
|
-
|
|
919
|
-
logger.info("[Step 5] Sending notifications to stakeholders")
|
|
920
|
-
|
|
921
|
-
# Create action items from gaps
|
|
922
|
-
action_items = []
|
|
923
|
-
action_id = 1
|
|
924
|
-
|
|
925
|
-
for gap in state["compliance_gaps"]:
|
|
926
|
-
assignee = determine_assignee(gap)
|
|
927
|
-
deadline = calculate_deadline(gap, state["days_until_audit"], state["next_audit_date"])
|
|
928
|
-
|
|
929
|
-
action_items.append(
|
|
930
|
-
{
|
|
931
|
-
"action_id": f"action_{action_id:03d}",
|
|
932
|
-
"gap_id": gap["gap_id"],
|
|
933
|
-
"description": gap["description"],
|
|
934
|
-
"action_required": gap["action_required"],
|
|
935
|
-
"severity": gap["severity"],
|
|
936
|
-
"assignee": assignee,
|
|
937
|
-
"assignee_email": get_assignee_email(assignee, state["hospital_id"]),
|
|
938
|
-
"deadline": deadline,
|
|
939
|
-
"estimated_time": gap["estimated_time_to_fix"],
|
|
940
|
-
"status": "pending",
|
|
941
|
-
"created_at": datetime.now().isoformat(),
|
|
942
|
-
}
|
|
943
|
-
)
|
|
944
|
-
action_id += 1
|
|
945
|
-
|
|
946
|
-
state["action_items"] = action_items
|
|
947
|
-
|
|
948
|
-
# Determine recipients based on severity
|
|
949
|
-
recipients = ["charge_nurse"]
|
|
950
|
-
if state["gap_severity_distribution"].get("critical", 0) > 0:
|
|
951
|
-
recipients.append("nurse_manager")
|
|
952
|
-
if state["gap_severity_distribution"].get("critical", 0) > 2:
|
|
953
|
-
recipients.append("cno") # Chief Nursing Officer for multiple critical issues
|
|
954
|
-
|
|
955
|
-
# Compose notification
|
|
956
|
-
notification = compose_notification(state, action_items)
|
|
957
|
-
|
|
958
|
-
# Send notification
|
|
959
|
-
# TODO: Integrate with actual notification system (email, SMS, Slack, etc.)
|
|
960
|
-
send_notification_to_recipients(notification, recipients, state["hospital_id"])
|
|
961
|
-
|
|
962
|
-
state["notification_sent"] = True
|
|
963
|
-
state["notification_recipients"] = recipients
|
|
964
|
-
state["notification_timestamp"] = datetime.now().isoformat()
|
|
965
|
-
state["last_updated"] = datetime.now().isoformat()
|
|
966
|
-
|
|
967
|
-
# Message
|
|
968
|
-
state["messages"].append(
|
|
969
|
-
AIMessage(
|
|
970
|
-
content=f"📧 Notifications sent to {len(recipients)} recipients: {', '.join(recipients)}"
|
|
971
|
-
)
|
|
972
|
-
)
|
|
973
|
-
|
|
974
|
-
# Audit trail
|
|
975
|
-
state["audit_trail"].append(
|
|
976
|
-
{
|
|
977
|
-
"timestamp": datetime.now().isoformat(),
|
|
978
|
-
"step": "notify",
|
|
979
|
-
"action": "Notifications sent",
|
|
980
|
-
"details": {
|
|
981
|
-
"recipients": recipients,
|
|
982
|
-
"action_item_count": len(action_items),
|
|
983
|
-
},
|
|
984
|
-
"user": "system",
|
|
985
|
-
}
|
|
986
|
-
)
|
|
987
|
-
|
|
988
|
-
logger.info(f"Notifications sent to: {recipients}")
|
|
989
|
-
|
|
990
|
-
return state
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
def schedule_continuous_monitoring(state: ComplianceAgentState) -> ComplianceAgentState:
|
|
994
|
-
"""
|
|
995
|
-
Step 6: Schedule periodic re-checks until audit
|
|
996
|
-
|
|
997
|
-
For positive outcomes:
|
|
998
|
-
- Regular monitoring tracks progress toward compliance
|
|
999
|
-
- Early detection of new gaps prevents last-minute scrambling
|
|
1000
|
-
- Trend analysis predicts audit readiness
|
|
1001
|
-
- Automated reminders keep team accountable
|
|
1002
|
-
"""
|
|
1003
|
-
|
|
1004
|
-
logger.info("[Step 6] Scheduling continuous monitoring")
|
|
1005
|
-
|
|
1006
|
-
days_until = state["days_until_audit"]
|
|
1007
|
-
|
|
1008
|
-
# Determine monitoring frequency based on time remaining
|
|
1009
|
-
if days_until > 90:
|
|
1010
|
-
frequency = "monthly"
|
|
1011
|
-
next_check_days = 30
|
|
1012
|
-
elif days_until > 60:
|
|
1013
|
-
frequency = "biweekly"
|
|
1014
|
-
next_check_days = 14
|
|
1015
|
-
elif days_until > 30:
|
|
1016
|
-
frequency = "weekly"
|
|
1017
|
-
next_check_days = 7
|
|
1018
|
-
else:
|
|
1019
|
-
frequency = "daily"
|
|
1020
|
-
next_check_days = 1
|
|
1021
|
-
|
|
1022
|
-
next_check_date = (datetime.now() + timedelta(days=next_check_days)).isoformat()
|
|
1023
|
-
|
|
1024
|
-
state["monitoring_scheduled"] = True
|
|
1025
|
-
state["monitoring_frequency"] = frequency
|
|
1026
|
-
state["next_check_date"] = next_check_date
|
|
1027
|
-
state["monitoring_until_date"] = state["next_audit_date"]
|
|
1028
|
-
state["last_updated"] = datetime.now().isoformat()
|
|
1029
|
-
|
|
1030
|
-
# Message
|
|
1031
|
-
state["messages"].append(
|
|
1032
|
-
AIMessage(
|
|
1033
|
-
content=f"⏰ Scheduled {frequency} monitoring until {state['next_audit_date']} "
|
|
1034
|
-
f"(next check: {next_check_date[:10]})"
|
|
1035
|
-
)
|
|
1036
|
-
)
|
|
1037
|
-
|
|
1038
|
-
# Audit trail
|
|
1039
|
-
state["audit_trail"].append(
|
|
1040
|
-
{
|
|
1041
|
-
"timestamp": datetime.now().isoformat(),
|
|
1042
|
-
"step": "schedule_monitor",
|
|
1043
|
-
"action": "Monitoring scheduled",
|
|
1044
|
-
"details": {
|
|
1045
|
-
"frequency": frequency,
|
|
1046
|
-
"next_check": next_check_date,
|
|
1047
|
-
"until_date": state["next_audit_date"],
|
|
1048
|
-
},
|
|
1049
|
-
"user": "system",
|
|
1050
|
-
}
|
|
1051
|
-
)
|
|
1052
|
-
|
|
1053
|
-
logger.info(f"Monitoring scheduled: {frequency} until {state['next_audit_date']}")
|
|
1054
|
-
|
|
1055
|
-
return state
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
# =============================================================================
|
|
1059
|
-
# Helper Functions
|
|
1060
|
-
# =============================================================================
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
def get_audit_requirements(audit_type: str) -> list[dict]:
|
|
1064
|
-
"""
|
|
1065
|
-
Get compliance requirements for audit type
|
|
1066
|
-
|
|
1067
|
-
TODO: Load from database or configuration file
|
|
1068
|
-
"""
|
|
1069
|
-
|
|
1070
|
-
# Example requirements for Joint Commission
|
|
1071
|
-
if audit_type == "joint_commission":
|
|
1072
|
-
return [
|
|
1073
|
-
{
|
|
1074
|
-
"id": "JC_MED_001",
|
|
1075
|
-
"category": "medication_safety",
|
|
1076
|
-
"description": "Medication administration records",
|
|
1077
|
-
},
|
|
1078
|
-
{
|
|
1079
|
-
"id": "JC_MED_002",
|
|
1080
|
-
"category": "medication_safety",
|
|
1081
|
-
"description": "High-risk medication double-checks",
|
|
1082
|
-
},
|
|
1083
|
-
{
|
|
1084
|
-
"id": "JC_DOC_001",
|
|
1085
|
-
"category": "documentation",
|
|
1086
|
-
"description": "Patient assessment documentation",
|
|
1087
|
-
},
|
|
1088
|
-
{
|
|
1089
|
-
"id": "JC_DOC_002",
|
|
1090
|
-
"category": "documentation",
|
|
1091
|
-
"description": "Nurse signature completeness",
|
|
1092
|
-
},
|
|
1093
|
-
{
|
|
1094
|
-
"id": "JC_SAF_001",
|
|
1095
|
-
"category": "patient_safety",
|
|
1096
|
-
"description": "Restraint order renewals",
|
|
1097
|
-
},
|
|
1098
|
-
{
|
|
1099
|
-
"id": "JC_SAF_002",
|
|
1100
|
-
"category": "patient_safety",
|
|
1101
|
-
"description": "Fall risk assessments",
|
|
1102
|
-
},
|
|
1103
|
-
{
|
|
1104
|
-
"id": "JC_INF_001",
|
|
1105
|
-
"category": "infection_control",
|
|
1106
|
-
"description": "Hand hygiene compliance",
|
|
1107
|
-
},
|
|
1108
|
-
{
|
|
1109
|
-
"id": "JC_INF_002",
|
|
1110
|
-
"category": "infection_control",
|
|
1111
|
-
"description": "Isolation protocol adherence",
|
|
1112
|
-
},
|
|
1113
|
-
# ... would have ~50 total requirements
|
|
1114
|
-
]
|
|
1115
|
-
|
|
1116
|
-
# Add other audit types as needed
|
|
1117
|
-
return []
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
def calculate_audit_readiness_score(state: ComplianceAgentState) -> float:
|
|
1121
|
-
"""
|
|
1122
|
-
Calculate overall audit readiness score (0-100)
|
|
1123
|
-
|
|
1124
|
-
Factors:
|
|
1125
|
-
- Compliance percentage (60% weight)
|
|
1126
|
-
- Gap severity (20% weight)
|
|
1127
|
-
- Time remaining (20% weight)
|
|
1128
|
-
"""
|
|
1129
|
-
|
|
1130
|
-
# Factor 1: Compliance percentage
|
|
1131
|
-
compliance_score = state["compliance_percentage"]
|
|
1132
|
-
|
|
1133
|
-
# Factor 2: Gap severity penalty
|
|
1134
|
-
severity_penalties = {
|
|
1135
|
-
"critical": 10, # -10 points per critical gap
|
|
1136
|
-
"high": 5,
|
|
1137
|
-
"medium": 2,
|
|
1138
|
-
"low": 0.5,
|
|
1139
|
-
}
|
|
1140
|
-
|
|
1141
|
-
severity_penalty = sum(
|
|
1142
|
-
count * severity_penalties.get(severity, 0)
|
|
1143
|
-
for severity, count in state["gap_severity_distribution"].items()
|
|
1144
|
-
)
|
|
1145
|
-
|
|
1146
|
-
gap_score = max(0, 100 - severity_penalty)
|
|
1147
|
-
|
|
1148
|
-
# Factor 3: Time remaining score
|
|
1149
|
-
days_until = state["days_until_audit"]
|
|
1150
|
-
if days_until >= 90:
|
|
1151
|
-
time_score = 100
|
|
1152
|
-
elif days_until >= 60:
|
|
1153
|
-
time_score = 80
|
|
1154
|
-
elif days_until >= 30:
|
|
1155
|
-
time_score = 60
|
|
1156
|
-
else:
|
|
1157
|
-
time_score = 40
|
|
1158
|
-
|
|
1159
|
-
# Weighted average
|
|
1160
|
-
readiness_score = compliance_score * 0.6 + gap_score * 0.2 + time_score * 0.2
|
|
1161
|
-
|
|
1162
|
-
return round(readiness_score, 1)
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
def determine_assignee(gap: dict) -> str:
|
|
1166
|
-
"""
|
|
1167
|
-
Determine who should be assigned to fix this gap
|
|
1168
|
-
|
|
1169
|
-
Based on category and severity
|
|
1170
|
-
"""
|
|
1171
|
-
|
|
1172
|
-
category = gap["category"]
|
|
1173
|
-
severity = gap["severity"]
|
|
1174
|
-
|
|
1175
|
-
if category == "medication_safety":
|
|
1176
|
-
if severity == "critical":
|
|
1177
|
-
return "nurse_manager" # Manager handles critical safety issues
|
|
1178
|
-
else:
|
|
1179
|
-
return "charge_nurse"
|
|
1180
|
-
|
|
1181
|
-
elif category == "documentation":
|
|
1182
|
-
return "charge_nurse" # Charge nurse coordinates documentation fixes
|
|
1183
|
-
|
|
1184
|
-
elif category == "patient_safety":
|
|
1185
|
-
if "restraint" in gap["item"].lower():
|
|
1186
|
-
return "provider" # Restraint orders require provider
|
|
1187
|
-
else:
|
|
1188
|
-
return "charge_nurse"
|
|
1189
|
-
|
|
1190
|
-
elif category == "infection_control":
|
|
1191
|
-
return "infection_control_nurse"
|
|
1192
|
-
|
|
1193
|
-
else:
|
|
1194
|
-
return "charge_nurse" # Default
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
def calculate_deadline(gap: dict, days_until_audit: int, audit_date: str) -> str:
|
|
1198
|
-
"""
|
|
1199
|
-
Calculate appropriate deadline for fixing gap
|
|
1200
|
-
|
|
1201
|
-
- Critical: 1 week or 25% of time remaining (whichever is sooner)
|
|
1202
|
-
- High: 2 weeks or 50% of time remaining
|
|
1203
|
-
- Medium: 1 month or 75% of time remaining
|
|
1204
|
-
- Low: 2 weeks before audit
|
|
1205
|
-
"""
|
|
1206
|
-
|
|
1207
|
-
severity = gap["severity"]
|
|
1208
|
-
|
|
1209
|
-
if severity == "critical":
|
|
1210
|
-
# 1 week or 25% of time
|
|
1211
|
-
deadline_days = min(7, days_until_audit // 4)
|
|
1212
|
-
elif severity == "high":
|
|
1213
|
-
# 2 weeks or 50% of time
|
|
1214
|
-
deadline_days = min(14, days_until_audit // 2)
|
|
1215
|
-
elif severity == "medium":
|
|
1216
|
-
# 1 month or 75% of time
|
|
1217
|
-
deadline_days = min(30, int(days_until_audit * 0.75))
|
|
1218
|
-
else: # low
|
|
1219
|
-
# 2 weeks before audit
|
|
1220
|
-
deadline_days = days_until_audit - 14
|
|
1221
|
-
|
|
1222
|
-
# Ensure deadline is at least tomorrow
|
|
1223
|
-
deadline_days = max(1, deadline_days)
|
|
1224
|
-
|
|
1225
|
-
deadline = datetime.now() + timedelta(days=deadline_days)
|
|
1226
|
-
|
|
1227
|
-
return deadline.isoformat()
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
def get_assignee_email(assignee: str, hospital_id: str) -> str:
|
|
1231
|
-
"""
|
|
1232
|
-
Get email address for assignee
|
|
1233
|
-
|
|
1234
|
-
TODO: Look up from hospital staff database
|
|
1235
|
-
"""
|
|
1236
|
-
|
|
1237
|
-
# Example mapping
|
|
1238
|
-
email_map = {
|
|
1239
|
-
"charge_nurse": f"charge.nurse@{hospital_id}.hospital.com",
|
|
1240
|
-
"nurse_manager": f"nurse.manager@{hospital_id}.hospital.com",
|
|
1241
|
-
"cno": f"cno@{hospital_id}.hospital.com",
|
|
1242
|
-
"provider": f"provider@{hospital_id}.hospital.com",
|
|
1243
|
-
"infection_control_nurse": f"infection.control@{hospital_id}.hospital.com",
|
|
1244
|
-
}
|
|
1245
|
-
|
|
1246
|
-
return email_map.get(assignee, f"{assignee}@{hospital_id}.hospital.com")
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
def compose_notification(state: ComplianceAgentState, action_items: list[dict]) -> dict:
|
|
1250
|
-
"""
|
|
1251
|
-
Compose notification with all relevant information
|
|
1252
|
-
"""
|
|
1253
|
-
|
|
1254
|
-
days_until = state["days_until_audit"]
|
|
1255
|
-
compliance_pct = state["compliance_percentage"]
|
|
1256
|
-
gaps = state["compliance_gaps"]
|
|
1257
|
-
readiness_score = state["documentation_package"]["audit_readiness_score"]
|
|
1258
|
-
|
|
1259
|
-
notification = {
|
|
1260
|
-
"type": "anticipatory_compliance_alert",
|
|
1261
|
-
"urgency": "high" if days_until < 60 else "medium",
|
|
1262
|
-
"title": f"{state['audit_type'].replace('_', ' ').title()} Audit Preparation",
|
|
1263
|
-
"summary": f"""
|
|
1264
|
-
📋 **{state["audit_type"].replace("_", " ").upper()} AUDIT PREPARATION**
|
|
1265
|
-
|
|
1266
|
-
**Audit Date:** {datetime.fromisoformat(state["next_audit_date"]).strftime("%B %d, %Y")}
|
|
1267
|
-
**Days Remaining:** {days_until} days
|
|
1268
|
-
**Audit Readiness Score:** {readiness_score:.1f}/100
|
|
1269
|
-
|
|
1270
|
-
---
|
|
1271
|
-
|
|
1272
|
-
✅ **COMPLIANCE STATUS**
|
|
1273
|
-
- Overall: {compliance_pct:.1f}% ({state["compliant_items"]}/{state["total_compliance_items"]} items)
|
|
1274
|
-
- Target: 95%+ for audit success
|
|
1275
|
-
|
|
1276
|
-
**Category Breakdown:**
|
|
1277
|
-
"""
|
|
1278
|
-
+ "\n".join(f"- {cat}: {score:.1f}%" for cat, score in state["category_scores"].items())
|
|
1279
|
-
+ f"""
|
|
1280
|
-
|
|
1281
|
-
---
|
|
1282
|
-
|
|
1283
|
-
⚠️ **GAPS REQUIRING ATTENTION ({len(gaps)} total)**
|
|
1284
|
-
"""
|
|
1285
|
-
+ "\n".join(f"[{g['severity'].upper()}] {g['description']}" for g in gaps[:5])
|
|
1286
|
-
+ (f"\n... and {len(gaps) - 5} more (see full report)" if len(gaps) > 5 else "")
|
|
1287
|
-
+ f"""
|
|
1288
|
-
|
|
1289
|
-
---
|
|
1290
|
-
|
|
1291
|
-
🎯 **ACTION ITEMS ({len(action_items)} tasks)**
|
|
1292
|
-
"""
|
|
1293
|
-
+ "\n".join(
|
|
1294
|
-
f"{i + 1}. [{item['severity'].upper()}] {item['description']}\n"
|
|
1295
|
-
f" → Assignee: {item['assignee']}\n"
|
|
1296
|
-
f" → Deadline: {datetime.fromisoformat(item['deadline']).strftime('%Y-%m-%d')}\n"
|
|
1297
|
-
f" → Time: {item['estimated_time']}"
|
|
1298
|
-
for i, item in enumerate(action_items[:3])
|
|
1299
|
-
)
|
|
1300
|
-
+ (f"\n... and {len(action_items) - 3} more action items" if len(action_items) > 3 else "")
|
|
1301
|
-
+ f"""
|
|
1302
|
-
|
|
1303
|
-
---
|
|
1304
|
-
|
|
1305
|
-
📂 **DOCUMENTATION PACKAGE**
|
|
1306
|
-
Pre-prepared documentation available at:
|
|
1307
|
-
{state["documentation_url"]}
|
|
1308
|
-
|
|
1309
|
-
Files included:
|
|
1310
|
-
"""
|
|
1311
|
-
+ "\n".join(f"- {f}" for f in state["documentation_files"])
|
|
1312
|
-
+ """
|
|
1313
|
-
|
|
1314
|
-
---
|
|
1315
|
-
|
|
1316
|
-
🤖 **ANTICIPATORY EMPATHY (Level 4)**
|
|
1317
|
-
|
|
1318
|
-
This alert was generated using predictive analytics based on your hospital's
|
|
1319
|
-
audit history. By preparing now, we have sufficient time to address all gaps
|
|
1320
|
-
without stress or rushed work during audit week.
|
|
1321
|
-
|
|
1322
|
-
**Prediction Details:**
|
|
1323
|
-
- Method: Historical cycle analysis
|
|
1324
|
-
- Confidence: {:.0%}
|
|
1325
|
-
- Next monitoring check: {}
|
|
1326
|
-
|
|
1327
|
-
**Questions?** Contact your compliance coordinator or reply to this message.
|
|
1328
|
-
""".format(
|
|
1329
|
-
state["prediction_confidence"],
|
|
1330
|
-
datetime.fromisoformat(state["next_check_date"]).strftime("%Y-%m-%d"),
|
|
1331
|
-
),
|
|
1332
|
-
"action_items": action_items,
|
|
1333
|
-
"documentation_url": state["documentation_url"],
|
|
1334
|
-
"priority": (
|
|
1335
|
-
"high" if state["gap_severity_distribution"].get("critical", 0) > 0 else "medium"
|
|
1336
|
-
),
|
|
1337
|
-
}
|
|
1338
|
-
|
|
1339
|
-
return notification
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
def send_notification_to_recipients(notification: dict, recipients: list[str], hospital_id: str):
|
|
1343
|
-
"""
|
|
1344
|
-
Send notification via configured channels
|
|
1345
|
-
|
|
1346
|
-
TODO: Integrate with actual notification system
|
|
1347
|
-
- Email (SMTP)
|
|
1348
|
-
- SMS (Twilio)
|
|
1349
|
-
- Slack/Teams (webhooks)
|
|
1350
|
-
- In-app notifications
|
|
1351
|
-
"""
|
|
1352
|
-
|
|
1353
|
-
logger.info(f"Sending notification to: {recipients}")
|
|
1354
|
-
|
|
1355
|
-
# Simulate sending
|
|
1356
|
-
for recipient in recipients:
|
|
1357
|
-
email = get_assignee_email(recipient, hospital_id)
|
|
1358
|
-
logger.info(f" → {recipient} ({email})")
|
|
1359
|
-
|
|
1360
|
-
# TODO: Actual email/SMS/webhook integration
|
|
1361
|
-
# send_email(to=email, subject=notification["title"], body=notification["summary"])
|
|
1362
|
-
|
|
1363
|
-
logger.info("Notifications sent successfully")
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
# =============================================================================
|
|
1367
|
-
# Main Entry Point
|
|
1368
|
-
# =============================================================================
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
async def run_compliance_agent(
|
|
1372
|
-
hospital_id: str, audit_type: str = "joint_commission"
|
|
1373
|
-
) -> ComplianceAgentState:
|
|
1374
|
-
"""
|
|
1375
|
-
Run the compliance anticipation agent
|
|
1376
|
-
|
|
1377
|
-
Args:
|
|
1378
|
-
hospital_id: Hospital/facility identifier
|
|
1379
|
-
audit_type: Type of audit to anticipate
|
|
1380
|
-
|
|
1381
|
-
Returns:
|
|
1382
|
-
Final agent state with all results
|
|
1383
|
-
"""
|
|
1384
|
-
|
|
1385
|
-
logger.info(f"Starting Compliance Anticipation Agent for {hospital_id} ({audit_type})")
|
|
1386
|
-
|
|
1387
|
-
# Create agent
|
|
1388
|
-
agent = create_compliance_agent()
|
|
1389
|
-
|
|
1390
|
-
# Initialize state
|
|
1391
|
-
initial_state = create_initial_state(hospital_id, audit_type)
|
|
1392
|
-
|
|
1393
|
-
# Run agent
|
|
1394
|
-
final_state = await agent.ainvoke(initial_state)
|
|
1395
|
-
|
|
1396
|
-
logger.info(
|
|
1397
|
-
f"Agent completed. Audit readiness score: "
|
|
1398
|
-
f"{final_state.get('documentation_package', {}).get('audit_readiness_score', 0):.1f}"
|
|
1399
|
-
)
|
|
1400
|
-
|
|
1401
|
-
return final_state
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
if __name__ == "__main__":
|
|
1405
|
-
import asyncio
|
|
1406
|
-
|
|
1407
|
-
# Example usage
|
|
1408
|
-
async def main():
|
|
1409
|
-
result = await run_compliance_agent(
|
|
1410
|
-
hospital_id="example_hospital_123", audit_type="joint_commission"
|
|
1411
|
-
)
|
|
1412
|
-
|
|
1413
|
-
print("\n" + "=" * 80)
|
|
1414
|
-
print("COMPLIANCE ANTICIPATION AGENT RESULTS")
|
|
1415
|
-
print("=" * 80)
|
|
1416
|
-
print(f"Audit Date: {result['next_audit_date']}")
|
|
1417
|
-
print(f"Days Until: {result['days_until_audit']}")
|
|
1418
|
-
print(f"Compliance: {result['compliance_percentage']:.1f}%")
|
|
1419
|
-
print(f"Gaps: {len(result['compliance_gaps'])}")
|
|
1420
|
-
print(f"Action Items: {len(result['action_items'])}")
|
|
1421
|
-
print(f"Documentation: {result['documentation_url']}")
|
|
1422
|
-
print(
|
|
1423
|
-
f"Audit Readiness: {result['documentation_package']['audit_readiness_score']:.1f}/100"
|
|
1424
|
-
)
|
|
1425
|
-
print("=" * 80)
|
|
1426
|
-
|
|
1427
|
-
asyncio.run(main())
|