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
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
"""Resilient Agent Wrapper
|
|
2
|
+
|
|
3
|
+
Applies production-ready resilience patterns (circuit breaker, retry, timeout,
|
|
4
|
+
fallback) to any agent created by the Agent Factory.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
from empathy_llm_toolkit.agent_factory import AgentFactory
|
|
8
|
+
from empathy_llm_toolkit.agent_factory.resilient import ResilientAgent, ResilienceConfig
|
|
9
|
+
|
|
10
|
+
factory = AgentFactory()
|
|
11
|
+
agent = factory.create_agent(name="researcher", role="researcher")
|
|
12
|
+
|
|
13
|
+
# Wrap with resilience
|
|
14
|
+
resilient_agent = ResilientAgent(agent, ResilienceConfig(
|
|
15
|
+
enable_circuit_breaker=True,
|
|
16
|
+
failure_threshold=3,
|
|
17
|
+
enable_retry=True,
|
|
18
|
+
max_attempts=3
|
|
19
|
+
))
|
|
20
|
+
|
|
21
|
+
result = await resilient_agent.invoke("Research AI trends")
|
|
22
|
+
|
|
23
|
+
Copyright 2025 Smart-AI-Memory
|
|
24
|
+
Licensed under Fair Source License 0.9
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
import asyncio
|
|
28
|
+
import functools
|
|
29
|
+
import logging
|
|
30
|
+
from dataclasses import dataclass, field
|
|
31
|
+
from typing import Any
|
|
32
|
+
|
|
33
|
+
from empathy_llm_toolkit.agent_factory.base import AgentConfig, BaseAgent
|
|
34
|
+
|
|
35
|
+
logger = logging.getLogger(__name__)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass
|
|
39
|
+
class ResilienceConfig:
|
|
40
|
+
"""Configuration for resilience patterns."""
|
|
41
|
+
|
|
42
|
+
# Circuit Breaker
|
|
43
|
+
enable_circuit_breaker: bool = True
|
|
44
|
+
failure_threshold: int = 3
|
|
45
|
+
reset_timeout: float = 60.0
|
|
46
|
+
half_open_max_calls: int = 3
|
|
47
|
+
|
|
48
|
+
# Retry
|
|
49
|
+
enable_retry: bool = True
|
|
50
|
+
max_attempts: int = 2
|
|
51
|
+
initial_delay: float = 1.0
|
|
52
|
+
backoff_factor: float = 2.0
|
|
53
|
+
max_delay: float = 30.0
|
|
54
|
+
jitter: bool = True
|
|
55
|
+
|
|
56
|
+
# Timeout
|
|
57
|
+
enable_timeout: bool = True
|
|
58
|
+
timeout_seconds: float = 30.0
|
|
59
|
+
|
|
60
|
+
# Fallback
|
|
61
|
+
enable_fallback: bool = False
|
|
62
|
+
fallback_value: Any = field(
|
|
63
|
+
default_factory=lambda: {
|
|
64
|
+
"output": "Service temporarily unavailable",
|
|
65
|
+
"metadata": {"fallback": True},
|
|
66
|
+
},
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
@classmethod
|
|
70
|
+
def from_agent_config(cls, config: AgentConfig) -> "ResilienceConfig":
|
|
71
|
+
"""Create ResilienceConfig from AgentConfig resilience fields."""
|
|
72
|
+
return cls(
|
|
73
|
+
enable_circuit_breaker=getattr(config, "resilience_enabled", False),
|
|
74
|
+
failure_threshold=getattr(config, "circuit_breaker_threshold", 3),
|
|
75
|
+
enable_retry=getattr(config, "resilience_enabled", False),
|
|
76
|
+
max_attempts=getattr(config, "retry_max_attempts", 2),
|
|
77
|
+
enable_timeout=getattr(config, "resilience_enabled", False),
|
|
78
|
+
timeout_seconds=getattr(config, "timeout_seconds", 30.0),
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class ResilientAgent(BaseAgent):
|
|
83
|
+
"""Agent wrapper that applies resilience patterns.
|
|
84
|
+
|
|
85
|
+
Wraps any BaseAgent implementation with:
|
|
86
|
+
- Circuit breaker: Prevents cascading failures
|
|
87
|
+
- Retry with backoff: Handles transient errors
|
|
88
|
+
- Timeout: Prevents hanging operations
|
|
89
|
+
- Fallback: Graceful degradation
|
|
90
|
+
|
|
91
|
+
The wrapper preserves the underlying agent's interface while adding
|
|
92
|
+
fault tolerance capabilities.
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
def __init__(self, agent: BaseAgent, config: ResilienceConfig | None = None):
|
|
96
|
+
"""Initialize resilient agent wrapper.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
agent: The underlying agent to wrap
|
|
100
|
+
config: Resilience configuration (uses defaults if not provided)
|
|
101
|
+
|
|
102
|
+
"""
|
|
103
|
+
# Initialize with wrapped agent's config
|
|
104
|
+
super().__init__(agent.config)
|
|
105
|
+
self._wrapped = agent
|
|
106
|
+
self._resilience_config = config or ResilienceConfig()
|
|
107
|
+
self._circuit_breaker: Any = None
|
|
108
|
+
self._setup_resilience()
|
|
109
|
+
|
|
110
|
+
def _setup_resilience(self) -> None:
|
|
111
|
+
"""Set up resilience decorators based on config."""
|
|
112
|
+
config = self._resilience_config
|
|
113
|
+
|
|
114
|
+
# Set up circuit breaker if enabled
|
|
115
|
+
if config.enable_circuit_breaker:
|
|
116
|
+
try:
|
|
117
|
+
from empathy_os.resilience import CircuitBreaker
|
|
118
|
+
|
|
119
|
+
self._circuit_breaker = CircuitBreaker(
|
|
120
|
+
name=f"agent_{self.name}",
|
|
121
|
+
failure_threshold=config.failure_threshold,
|
|
122
|
+
reset_timeout=config.reset_timeout,
|
|
123
|
+
half_open_max_calls=config.half_open_max_calls,
|
|
124
|
+
)
|
|
125
|
+
except ImportError:
|
|
126
|
+
logger.warning("empathy_os.resilience not available, circuit breaker disabled")
|
|
127
|
+
|
|
128
|
+
async def invoke(self, input_data: str | dict, context: dict | None = None) -> dict:
|
|
129
|
+
"""Invoke the agent with resilience patterns applied.
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
input_data: User input or structured data
|
|
133
|
+
context: Optional context (previous results, shared state)
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
Dict with at least {"output": str, "metadata": dict}
|
|
137
|
+
|
|
138
|
+
Raises:
|
|
139
|
+
CircuitOpenError: If circuit breaker is open
|
|
140
|
+
asyncio.TimeoutError: If operation times out and no fallback
|
|
141
|
+
Exception: If all retries exhausted and no fallback
|
|
142
|
+
|
|
143
|
+
"""
|
|
144
|
+
config = self._resilience_config
|
|
145
|
+
|
|
146
|
+
# Build the resilient call chain
|
|
147
|
+
async def _call():
|
|
148
|
+
return await self._wrapped.invoke(input_data, context)
|
|
149
|
+
|
|
150
|
+
# Apply timeout
|
|
151
|
+
if config.enable_timeout:
|
|
152
|
+
_call = self._with_timeout(_call, config.timeout_seconds)
|
|
153
|
+
|
|
154
|
+
# Apply retry
|
|
155
|
+
if config.enable_retry:
|
|
156
|
+
_call = self._with_retry(
|
|
157
|
+
_call,
|
|
158
|
+
config.max_attempts,
|
|
159
|
+
config.initial_delay,
|
|
160
|
+
config.backoff_factor,
|
|
161
|
+
config.max_delay,
|
|
162
|
+
config.jitter,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
# Apply circuit breaker
|
|
166
|
+
if config.enable_circuit_breaker and self._circuit_breaker:
|
|
167
|
+
_call = self._with_circuit_breaker(_call)
|
|
168
|
+
|
|
169
|
+
# Execute with optional fallback
|
|
170
|
+
try:
|
|
171
|
+
result = await _call()
|
|
172
|
+
# Add resilience metadata
|
|
173
|
+
if "metadata" in result:
|
|
174
|
+
result["metadata"]["resilience"] = {
|
|
175
|
+
"circuit_breaker_enabled": config.enable_circuit_breaker,
|
|
176
|
+
"retry_enabled": config.enable_retry,
|
|
177
|
+
"timeout_enabled": config.enable_timeout,
|
|
178
|
+
}
|
|
179
|
+
return dict(result)
|
|
180
|
+
except Exception as e:
|
|
181
|
+
if config.enable_fallback:
|
|
182
|
+
logger.warning(f"Agent {self.name} failed, using fallback: {e}")
|
|
183
|
+
fallback = config.fallback_value
|
|
184
|
+
if callable(fallback):
|
|
185
|
+
return dict(fallback(input_data, context, e))
|
|
186
|
+
return dict(fallback) if isinstance(fallback, dict) else {"output": fallback}
|
|
187
|
+
raise
|
|
188
|
+
|
|
189
|
+
async def stream(self, input_data: str | dict, context: dict | None = None):
|
|
190
|
+
"""Stream agent response with resilience patterns.
|
|
191
|
+
|
|
192
|
+
Note: Streaming has limited resilience support (timeout only).
|
|
193
|
+
Circuit breaker and retry work at the full response level.
|
|
194
|
+
"""
|
|
195
|
+
config = self._resilience_config
|
|
196
|
+
|
|
197
|
+
async def _stream():
|
|
198
|
+
async for chunk in self._wrapped.stream(input_data, context):
|
|
199
|
+
yield chunk
|
|
200
|
+
|
|
201
|
+
# Apply timeout to entire stream
|
|
202
|
+
if config.enable_timeout:
|
|
203
|
+
try:
|
|
204
|
+
async with asyncio.timeout(config.timeout_seconds): # type: ignore[attr-defined]
|
|
205
|
+
async for chunk in _stream():
|
|
206
|
+
yield chunk
|
|
207
|
+
except asyncio.TimeoutError:
|
|
208
|
+
if config.enable_fallback:
|
|
209
|
+
yield {"output": "Stream timed out", "metadata": {"fallback": True}}
|
|
210
|
+
else:
|
|
211
|
+
raise
|
|
212
|
+
else:
|
|
213
|
+
async for chunk in _stream():
|
|
214
|
+
yield chunk
|
|
215
|
+
|
|
216
|
+
def _with_timeout(self, func, timeout_seconds: float):
|
|
217
|
+
"""Wrap function with timeout."""
|
|
218
|
+
|
|
219
|
+
@functools.wraps(func)
|
|
220
|
+
async def wrapper():
|
|
221
|
+
return await asyncio.wait_for(func(), timeout=timeout_seconds)
|
|
222
|
+
|
|
223
|
+
return wrapper
|
|
224
|
+
|
|
225
|
+
def _with_retry(
|
|
226
|
+
self,
|
|
227
|
+
func,
|
|
228
|
+
max_attempts: int,
|
|
229
|
+
initial_delay: float,
|
|
230
|
+
backoff_factor: float,
|
|
231
|
+
max_delay: float,
|
|
232
|
+
jitter: bool,
|
|
233
|
+
):
|
|
234
|
+
"""Wrap function with retry logic."""
|
|
235
|
+
import random
|
|
236
|
+
|
|
237
|
+
@functools.wraps(func)
|
|
238
|
+
async def wrapper():
|
|
239
|
+
last_exception = None
|
|
240
|
+
delay = initial_delay
|
|
241
|
+
|
|
242
|
+
for attempt in range(max_attempts):
|
|
243
|
+
try:
|
|
244
|
+
return await func()
|
|
245
|
+
except asyncio.TimeoutError:
|
|
246
|
+
# Don't retry timeouts by default
|
|
247
|
+
raise
|
|
248
|
+
except Exception as e:
|
|
249
|
+
last_exception = e
|
|
250
|
+
if attempt < max_attempts - 1:
|
|
251
|
+
actual_delay = delay
|
|
252
|
+
if jitter:
|
|
253
|
+
actual_delay = delay * (0.5 + random.random())
|
|
254
|
+
actual_delay = min(actual_delay, max_delay)
|
|
255
|
+
logger.debug(
|
|
256
|
+
f"Agent {self.name} attempt {attempt + 1} failed, "
|
|
257
|
+
f"retrying in {actual_delay:.2f}s: {e}",
|
|
258
|
+
)
|
|
259
|
+
await asyncio.sleep(actual_delay)
|
|
260
|
+
delay = min(delay * backoff_factor, max_delay)
|
|
261
|
+
|
|
262
|
+
raise last_exception
|
|
263
|
+
|
|
264
|
+
return wrapper
|
|
265
|
+
|
|
266
|
+
def _with_circuit_breaker(self, func):
|
|
267
|
+
"""Wrap function with circuit breaker."""
|
|
268
|
+
|
|
269
|
+
@functools.wraps(func)
|
|
270
|
+
async def wrapper():
|
|
271
|
+
from empathy_os.resilience import CircuitOpenError
|
|
272
|
+
|
|
273
|
+
# Check if circuit is open (failing fast)
|
|
274
|
+
if self._circuit_breaker.is_open:
|
|
275
|
+
reset_time = self._circuit_breaker.get_time_until_reset()
|
|
276
|
+
raise CircuitOpenError(
|
|
277
|
+
name=f"agent_{self.name}",
|
|
278
|
+
reset_time=reset_time,
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
try:
|
|
282
|
+
result = await func()
|
|
283
|
+
self._circuit_breaker.record_success()
|
|
284
|
+
return result
|
|
285
|
+
except Exception as e:
|
|
286
|
+
self._circuit_breaker.record_failure(e)
|
|
287
|
+
raise
|
|
288
|
+
|
|
289
|
+
return wrapper
|
|
290
|
+
|
|
291
|
+
# Delegate other methods to wrapped agent
|
|
292
|
+
def add_tool(self, tool: Any) -> None:
|
|
293
|
+
"""Add a tool to the wrapped agent."""
|
|
294
|
+
self._wrapped.add_tool(tool)
|
|
295
|
+
|
|
296
|
+
def get_conversation_history(self) -> list[dict]:
|
|
297
|
+
"""Get conversation history from wrapped agent."""
|
|
298
|
+
return self._wrapped.get_conversation_history()
|
|
299
|
+
|
|
300
|
+
def clear_history(self) -> None:
|
|
301
|
+
"""Clear conversation history in wrapped agent."""
|
|
302
|
+
self._wrapped.clear_history()
|
|
303
|
+
|
|
304
|
+
@property
|
|
305
|
+
def model(self) -> str:
|
|
306
|
+
"""Get the model being used by wrapped agent."""
|
|
307
|
+
return self._wrapped.model
|
|
308
|
+
|
|
309
|
+
@property
|
|
310
|
+
def circuit_state(self) -> str | None:
|
|
311
|
+
"""Get current circuit breaker state."""
|
|
312
|
+
if self._circuit_breaker:
|
|
313
|
+
return str(self._circuit_breaker.state.value)
|
|
314
|
+
return None
|
|
315
|
+
|
|
316
|
+
def reset_circuit_breaker(self) -> None:
|
|
317
|
+
"""Manually reset the circuit breaker."""
|
|
318
|
+
if self._circuit_breaker:
|
|
319
|
+
self._circuit_breaker.reset()
|
|
320
|
+
logger.info(f"Circuit breaker reset for agent {self.name}")
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Claude Memory Integration Module
|
|
1
|
+
"""Claude Memory Integration Module
|
|
3
2
|
|
|
4
3
|
Reads and integrates Claude Code's CLAUDE.md memory files with the Empathy Framework.
|
|
5
4
|
Supports hierarchical memory loading (Enterprise → Project → User) and @import directives.
|
|
@@ -64,8 +63,7 @@ class MemoryFile:
|
|
|
64
63
|
|
|
65
64
|
|
|
66
65
|
class ClaudeMemoryLoader:
|
|
67
|
-
"""
|
|
68
|
-
Loads and manages Claude Code memory files (CLAUDE.md).
|
|
66
|
+
"""Loads and manages Claude Code memory files (CLAUDE.md).
|
|
69
67
|
|
|
70
68
|
Follows Claude Code's hierarchical memory system:
|
|
71
69
|
1. Enterprise memory (organization-wide)
|
|
@@ -81,8 +79,7 @@ class ClaudeMemoryLoader:
|
|
|
81
79
|
self._import_stack: list[str] = [] # Track imports to detect cycles
|
|
82
80
|
|
|
83
81
|
def load_all_memory(self, project_root: str | None = None) -> str:
|
|
84
|
-
"""
|
|
85
|
-
Load all Claude memory files and return combined content.
|
|
82
|
+
"""Load all Claude memory files and return combined content.
|
|
86
83
|
|
|
87
84
|
Args:
|
|
88
85
|
project_root: Project root directory (defaults to cwd)
|
|
@@ -94,6 +91,7 @@ class ClaudeMemoryLoader:
|
|
|
94
91
|
loader = ClaudeMemoryLoader(ClaudeMemoryConfig(enabled=True))
|
|
95
92
|
memory = loader.load_all_memory("/path/to/project")
|
|
96
93
|
# Use memory in LLM system prompt
|
|
94
|
+
|
|
97
95
|
"""
|
|
98
96
|
if not self.config.enabled:
|
|
99
97
|
logger.debug("claude_memory_disabled")
|
|
@@ -185,8 +183,7 @@ class ClaudeMemoryLoader:
|
|
|
185
183
|
return None
|
|
186
184
|
|
|
187
185
|
def _load_memory_file(self, file_path: str, level: str, depth: int = 0) -> MemoryFile | None:
|
|
188
|
-
"""
|
|
189
|
-
Load a single memory file and process imports.
|
|
186
|
+
"""Load a single memory file and process imports.
|
|
190
187
|
|
|
191
188
|
Args:
|
|
192
189
|
file_path: Path to CLAUDE.md file
|
|
@@ -195,6 +192,7 @@ class ClaudeMemoryLoader:
|
|
|
195
192
|
|
|
196
193
|
Returns:
|
|
197
194
|
MemoryFile object or None if failed
|
|
195
|
+
|
|
198
196
|
"""
|
|
199
197
|
# Check depth limit
|
|
200
198
|
if depth > self.config.max_import_depth:
|
|
@@ -270,8 +268,7 @@ class ClaudeMemoryLoader:
|
|
|
270
268
|
return None
|
|
271
269
|
|
|
272
270
|
def _process_imports(self, content: str, base_dir: Path, depth: int) -> tuple[str, list[str]]:
|
|
273
|
-
"""
|
|
274
|
-
Process @import directives in memory content.
|
|
271
|
+
"""Process @import directives in memory content.
|
|
275
272
|
|
|
276
273
|
Supports syntax: @path/to/file.md
|
|
277
274
|
|
|
@@ -282,6 +279,7 @@ class ClaudeMemoryLoader:
|
|
|
282
279
|
|
|
283
280
|
Returns:
|
|
284
281
|
(processed_content, list_of_imported_paths)
|
|
282
|
+
|
|
285
283
|
"""
|
|
286
284
|
# Match @import syntax: @path/to/file
|
|
287
285
|
import_pattern = re.compile(r"^@([^\s]+)$", re.MULTILINE)
|
|
@@ -301,7 +299,9 @@ class ClaudeMemoryLoader:
|
|
|
301
299
|
if resolved_path.exists():
|
|
302
300
|
# Recursively load imported file
|
|
303
301
|
imported_file = self._load_memory_file(
|
|
304
|
-
str(resolved_path),
|
|
302
|
+
str(resolved_path),
|
|
303
|
+
level="import",
|
|
304
|
+
depth=depth + 1,
|
|
305
305
|
)
|
|
306
306
|
|
|
307
307
|
if imported_file:
|
|
@@ -322,8 +322,7 @@ class ClaudeMemoryLoader:
|
|
|
322
322
|
return "\n".join(processed_lines), imports
|
|
323
323
|
|
|
324
324
|
def _combine_memory_files(self, memory_files: list[MemoryFile]) -> str:
|
|
325
|
-
"""
|
|
326
|
-
Combine multiple memory files into a single memory string.
|
|
325
|
+
"""Combine multiple memory files into a single memory string.
|
|
327
326
|
|
|
328
327
|
Files are combined in load order with clear section markers.
|
|
329
328
|
"""
|
|
@@ -355,8 +354,7 @@ class ClaudeMemoryLoader:
|
|
|
355
354
|
|
|
356
355
|
|
|
357
356
|
def create_default_project_memory(project_root: str, framework: str = "empathy"):
|
|
358
|
-
"""
|
|
359
|
-
Create a default .claude/CLAUDE.md file for a project.
|
|
357
|
+
"""Create a default .claude/CLAUDE.md file for a project.
|
|
360
358
|
|
|
361
359
|
Args:
|
|
362
360
|
project_root: Project root directory
|
|
@@ -364,6 +362,7 @@ def create_default_project_memory(project_root: str, framework: str = "empathy")
|
|
|
364
362
|
|
|
365
363
|
Example:
|
|
366
364
|
create_default_project_memory("/path/to/project")
|
|
365
|
+
|
|
367
366
|
"""
|
|
368
367
|
project_path = Path(project_root)
|
|
369
368
|
claude_dir = project_path / ".claude"
|