empathy-framework 3.2.3__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.
Files changed (328) hide show
  1. coach_wizards/__init__.py +11 -12
  2. coach_wizards/accessibility_wizard.py +12 -12
  3. coach_wizards/api_wizard.py +12 -12
  4. coach_wizards/base_wizard.py +26 -20
  5. coach_wizards/cicd_wizard.py +15 -13
  6. coach_wizards/code_reviewer_README.md +60 -0
  7. coach_wizards/code_reviewer_wizard.py +180 -0
  8. coach_wizards/compliance_wizard.py +12 -12
  9. coach_wizards/database_wizard.py +12 -12
  10. coach_wizards/debugging_wizard.py +12 -12
  11. coach_wizards/documentation_wizard.py +12 -12
  12. coach_wizards/generate_wizards.py +1 -2
  13. coach_wizards/localization_wizard.py +101 -19
  14. coach_wizards/migration_wizard.py +12 -12
  15. coach_wizards/monitoring_wizard.py +12 -12
  16. coach_wizards/observability_wizard.py +12 -12
  17. coach_wizards/performance_wizard.py +12 -12
  18. coach_wizards/prompt_engineering_wizard.py +22 -25
  19. coach_wizards/refactoring_wizard.py +12 -12
  20. coach_wizards/scaling_wizard.py +12 -12
  21. coach_wizards/security_wizard.py +12 -12
  22. coach_wizards/testing_wizard.py +12 -12
  23. {empathy_framework-3.2.3.dist-info → empathy_framework-3.8.2.dist-info}/METADATA +513 -58
  24. empathy_framework-3.8.2.dist-info/RECORD +333 -0
  25. empathy_framework-3.8.2.dist-info/entry_points.txt +22 -0
  26. {empathy_framework-3.2.3.dist-info → empathy_framework-3.8.2.dist-info}/top_level.txt +5 -1
  27. empathy_healthcare_plugin/__init__.py +1 -2
  28. empathy_healthcare_plugin/monitors/__init__.py +9 -0
  29. empathy_healthcare_plugin/monitors/clinical_protocol_monitor.py +315 -0
  30. empathy_healthcare_plugin/monitors/monitoring/__init__.py +44 -0
  31. empathy_healthcare_plugin/monitors/monitoring/protocol_checker.py +300 -0
  32. empathy_healthcare_plugin/monitors/monitoring/protocol_loader.py +214 -0
  33. empathy_healthcare_plugin/monitors/monitoring/sensor_parsers.py +306 -0
  34. empathy_healthcare_plugin/monitors/monitoring/trajectory_analyzer.py +389 -0
  35. empathy_llm_toolkit/__init__.py +7 -7
  36. empathy_llm_toolkit/agent_factory/__init__.py +53 -0
  37. empathy_llm_toolkit/agent_factory/adapters/__init__.py +85 -0
  38. empathy_llm_toolkit/agent_factory/adapters/autogen_adapter.py +312 -0
  39. empathy_llm_toolkit/agent_factory/adapters/crewai_adapter.py +454 -0
  40. empathy_llm_toolkit/agent_factory/adapters/haystack_adapter.py +298 -0
  41. empathy_llm_toolkit/agent_factory/adapters/langchain_adapter.py +362 -0
  42. empathy_llm_toolkit/agent_factory/adapters/langgraph_adapter.py +333 -0
  43. empathy_llm_toolkit/agent_factory/adapters/native.py +228 -0
  44. empathy_llm_toolkit/agent_factory/adapters/wizard_adapter.py +426 -0
  45. empathy_llm_toolkit/agent_factory/base.py +305 -0
  46. empathy_llm_toolkit/agent_factory/crews/__init__.py +67 -0
  47. empathy_llm_toolkit/agent_factory/crews/code_review.py +1113 -0
  48. empathy_llm_toolkit/agent_factory/crews/health_check.py +1246 -0
  49. empathy_llm_toolkit/agent_factory/crews/refactoring.py +1128 -0
  50. empathy_llm_toolkit/agent_factory/crews/security_audit.py +1018 -0
  51. empathy_llm_toolkit/agent_factory/decorators.py +286 -0
  52. empathy_llm_toolkit/agent_factory/factory.py +558 -0
  53. empathy_llm_toolkit/agent_factory/framework.py +192 -0
  54. empathy_llm_toolkit/agent_factory/memory_integration.py +324 -0
  55. empathy_llm_toolkit/agent_factory/resilient.py +320 -0
  56. empathy_llm_toolkit/claude_memory.py +14 -15
  57. empathy_llm_toolkit/cli/__init__.py +8 -0
  58. empathy_llm_toolkit/cli/sync_claude.py +487 -0
  59. empathy_llm_toolkit/code_health.py +177 -22
  60. empathy_llm_toolkit/config/__init__.py +29 -0
  61. empathy_llm_toolkit/config/unified.py +295 -0
  62. empathy_llm_toolkit/contextual_patterns.py +11 -12
  63. empathy_llm_toolkit/core.py +51 -49
  64. empathy_llm_toolkit/git_pattern_extractor.py +16 -12
  65. empathy_llm_toolkit/levels.py +6 -13
  66. empathy_llm_toolkit/pattern_confidence.py +14 -18
  67. empathy_llm_toolkit/pattern_resolver.py +10 -12
  68. empathy_llm_toolkit/pattern_summary.py +13 -11
  69. empathy_llm_toolkit/providers.py +194 -28
  70. empathy_llm_toolkit/routing/__init__.py +32 -0
  71. empathy_llm_toolkit/routing/model_router.py +362 -0
  72. empathy_llm_toolkit/security/IMPLEMENTATION_SUMMARY.md +413 -0
  73. empathy_llm_toolkit/security/PHASE2_COMPLETE.md +384 -0
  74. empathy_llm_toolkit/security/PHASE2_SECRETS_DETECTOR_COMPLETE.md +271 -0
  75. empathy_llm_toolkit/security/QUICK_REFERENCE.md +316 -0
  76. empathy_llm_toolkit/security/README.md +262 -0
  77. empathy_llm_toolkit/security/__init__.py +62 -0
  78. empathy_llm_toolkit/security/audit_logger.py +929 -0
  79. empathy_llm_toolkit/security/audit_logger_example.py +152 -0
  80. empathy_llm_toolkit/security/pii_scrubber.py +640 -0
  81. empathy_llm_toolkit/security/secrets_detector.py +678 -0
  82. empathy_llm_toolkit/security/secrets_detector_example.py +304 -0
  83. empathy_llm_toolkit/security/secure_memdocs.py +1192 -0
  84. empathy_llm_toolkit/security/secure_memdocs_example.py +278 -0
  85. empathy_llm_toolkit/session_status.py +18 -20
  86. empathy_llm_toolkit/state.py +20 -21
  87. empathy_llm_toolkit/wizards/__init__.py +38 -0
  88. empathy_llm_toolkit/wizards/base_wizard.py +364 -0
  89. empathy_llm_toolkit/wizards/customer_support_wizard.py +190 -0
  90. empathy_llm_toolkit/wizards/healthcare_wizard.py +362 -0
  91. empathy_llm_toolkit/wizards/patient_assessment_README.md +64 -0
  92. empathy_llm_toolkit/wizards/patient_assessment_wizard.py +193 -0
  93. empathy_llm_toolkit/wizards/technology_wizard.py +194 -0
  94. empathy_os/__init__.py +76 -77
  95. empathy_os/adaptive/__init__.py +13 -0
  96. empathy_os/adaptive/task_complexity.py +127 -0
  97. empathy_os/{monitoring.py → agent_monitoring.py} +27 -27
  98. empathy_os/cache/__init__.py +117 -0
  99. empathy_os/cache/base.py +166 -0
  100. empathy_os/cache/dependency_manager.py +253 -0
  101. empathy_os/cache/hash_only.py +248 -0
  102. empathy_os/cache/hybrid.py +390 -0
  103. empathy_os/cache/storage.py +282 -0
  104. empathy_os/cli.py +515 -109
  105. empathy_os/cli_unified.py +189 -42
  106. empathy_os/config/__init__.py +63 -0
  107. empathy_os/config/xml_config.py +239 -0
  108. empathy_os/config.py +87 -36
  109. empathy_os/coordination.py +48 -54
  110. empathy_os/core.py +90 -99
  111. empathy_os/cost_tracker.py +20 -23
  112. empathy_os/dashboard/__init__.py +15 -0
  113. empathy_os/dashboard/server.py +743 -0
  114. empathy_os/discovery.py +9 -11
  115. empathy_os/emergence.py +20 -21
  116. empathy_os/exceptions.py +18 -30
  117. empathy_os/feedback_loops.py +27 -30
  118. empathy_os/levels.py +31 -34
  119. empathy_os/leverage_points.py +27 -28
  120. empathy_os/logging_config.py +11 -12
  121. empathy_os/memory/__init__.py +195 -0
  122. empathy_os/memory/claude_memory.py +466 -0
  123. empathy_os/memory/config.py +224 -0
  124. empathy_os/memory/control_panel.py +1298 -0
  125. empathy_os/memory/edges.py +179 -0
  126. empathy_os/memory/graph.py +567 -0
  127. empathy_os/memory/long_term.py +1194 -0
  128. empathy_os/memory/nodes.py +179 -0
  129. empathy_os/memory/redis_bootstrap.py +540 -0
  130. empathy_os/memory/security/__init__.py +31 -0
  131. empathy_os/memory/security/audit_logger.py +930 -0
  132. empathy_os/memory/security/pii_scrubber.py +640 -0
  133. empathy_os/memory/security/secrets_detector.py +678 -0
  134. empathy_os/memory/short_term.py +2119 -0
  135. empathy_os/memory/storage/__init__.py +15 -0
  136. empathy_os/memory/summary_index.py +583 -0
  137. empathy_os/memory/unified.py +619 -0
  138. empathy_os/metrics/__init__.py +12 -0
  139. empathy_os/metrics/prompt_metrics.py +190 -0
  140. empathy_os/models/__init__.py +136 -0
  141. empathy_os/models/__main__.py +13 -0
  142. empathy_os/models/cli.py +655 -0
  143. empathy_os/models/empathy_executor.py +354 -0
  144. empathy_os/models/executor.py +252 -0
  145. empathy_os/models/fallback.py +671 -0
  146. empathy_os/models/provider_config.py +563 -0
  147. empathy_os/models/registry.py +382 -0
  148. empathy_os/models/tasks.py +302 -0
  149. empathy_os/models/telemetry.py +548 -0
  150. empathy_os/models/token_estimator.py +378 -0
  151. empathy_os/models/validation.py +274 -0
  152. empathy_os/monitoring/__init__.py +52 -0
  153. empathy_os/monitoring/alerts.py +23 -0
  154. empathy_os/monitoring/alerts_cli.py +268 -0
  155. empathy_os/monitoring/multi_backend.py +271 -0
  156. empathy_os/monitoring/otel_backend.py +363 -0
  157. empathy_os/optimization/__init__.py +19 -0
  158. empathy_os/optimization/context_optimizer.py +272 -0
  159. empathy_os/pattern_library.py +29 -28
  160. empathy_os/persistence.py +30 -34
  161. empathy_os/platform_utils.py +261 -0
  162. empathy_os/plugins/__init__.py +28 -0
  163. empathy_os/plugins/base.py +361 -0
  164. empathy_os/plugins/registry.py +268 -0
  165. empathy_os/project_index/__init__.py +30 -0
  166. empathy_os/project_index/cli.py +335 -0
  167. empathy_os/project_index/crew_integration.py +430 -0
  168. empathy_os/project_index/index.py +425 -0
  169. empathy_os/project_index/models.py +501 -0
  170. empathy_os/project_index/reports.py +473 -0
  171. empathy_os/project_index/scanner.py +538 -0
  172. empathy_os/prompts/__init__.py +61 -0
  173. empathy_os/prompts/config.py +77 -0
  174. empathy_os/prompts/context.py +177 -0
  175. empathy_os/prompts/parser.py +285 -0
  176. empathy_os/prompts/registry.py +313 -0
  177. empathy_os/prompts/templates.py +208 -0
  178. empathy_os/redis_config.py +144 -58
  179. empathy_os/redis_memory.py +53 -56
  180. empathy_os/resilience/__init__.py +56 -0
  181. empathy_os/resilience/circuit_breaker.py +256 -0
  182. empathy_os/resilience/fallback.py +179 -0
  183. empathy_os/resilience/health.py +300 -0
  184. empathy_os/resilience/retry.py +209 -0
  185. empathy_os/resilience/timeout.py +135 -0
  186. empathy_os/routing/__init__.py +43 -0
  187. empathy_os/routing/chain_executor.py +433 -0
  188. empathy_os/routing/classifier.py +217 -0
  189. empathy_os/routing/smart_router.py +234 -0
  190. empathy_os/routing/wizard_registry.py +307 -0
  191. empathy_os/templates.py +12 -11
  192. empathy_os/trust/__init__.py +28 -0
  193. empathy_os/trust/circuit_breaker.py +579 -0
  194. empathy_os/trust_building.py +44 -36
  195. empathy_os/validation/__init__.py +19 -0
  196. empathy_os/validation/xml_validator.py +281 -0
  197. empathy_os/wizard_factory_cli.py +170 -0
  198. empathy_os/{workflows.py → workflow_commands.py} +123 -31
  199. empathy_os/workflows/__init__.py +360 -0
  200. empathy_os/workflows/base.py +1660 -0
  201. empathy_os/workflows/bug_predict.py +962 -0
  202. empathy_os/workflows/code_review.py +960 -0
  203. empathy_os/workflows/code_review_adapters.py +310 -0
  204. empathy_os/workflows/code_review_pipeline.py +720 -0
  205. empathy_os/workflows/config.py +600 -0
  206. empathy_os/workflows/dependency_check.py +648 -0
  207. empathy_os/workflows/document_gen.py +1069 -0
  208. empathy_os/workflows/documentation_orchestrator.py +1205 -0
  209. empathy_os/workflows/health_check.py +679 -0
  210. empathy_os/workflows/keyboard_shortcuts/__init__.py +39 -0
  211. empathy_os/workflows/keyboard_shortcuts/generators.py +386 -0
  212. empathy_os/workflows/keyboard_shortcuts/parsers.py +414 -0
  213. empathy_os/workflows/keyboard_shortcuts/prompts.py +295 -0
  214. empathy_os/workflows/keyboard_shortcuts/schema.py +193 -0
  215. empathy_os/workflows/keyboard_shortcuts/workflow.py +505 -0
  216. empathy_os/workflows/manage_documentation.py +804 -0
  217. empathy_os/workflows/new_sample_workflow1.py +146 -0
  218. empathy_os/workflows/new_sample_workflow1_README.md +150 -0
  219. empathy_os/workflows/perf_audit.py +687 -0
  220. empathy_os/workflows/pr_review.py +748 -0
  221. empathy_os/workflows/progress.py +445 -0
  222. empathy_os/workflows/progress_server.py +322 -0
  223. empathy_os/workflows/refactor_plan.py +693 -0
  224. empathy_os/workflows/release_prep.py +808 -0
  225. empathy_os/workflows/research_synthesis.py +404 -0
  226. empathy_os/workflows/secure_release.py +585 -0
  227. empathy_os/workflows/security_adapters.py +297 -0
  228. empathy_os/workflows/security_audit.py +1046 -0
  229. empathy_os/workflows/step_config.py +234 -0
  230. empathy_os/workflows/test5.py +125 -0
  231. empathy_os/workflows/test5_README.md +158 -0
  232. empathy_os/workflows/test_gen.py +1855 -0
  233. empathy_os/workflows/test_lifecycle.py +526 -0
  234. empathy_os/workflows/test_maintenance.py +626 -0
  235. empathy_os/workflows/test_maintenance_cli.py +590 -0
  236. empathy_os/workflows/test_maintenance_crew.py +821 -0
  237. empathy_os/workflows/xml_enhanced_crew.py +285 -0
  238. empathy_software_plugin/__init__.py +1 -2
  239. empathy_software_plugin/cli/__init__.py +120 -0
  240. empathy_software_plugin/cli/inspect.py +362 -0
  241. empathy_software_plugin/cli.py +35 -26
  242. empathy_software_plugin/plugin.py +4 -8
  243. empathy_software_plugin/wizards/__init__.py +42 -0
  244. empathy_software_plugin/wizards/advanced_debugging_wizard.py +392 -0
  245. empathy_software_plugin/wizards/agent_orchestration_wizard.py +511 -0
  246. empathy_software_plugin/wizards/ai_collaboration_wizard.py +503 -0
  247. empathy_software_plugin/wizards/ai_context_wizard.py +441 -0
  248. empathy_software_plugin/wizards/ai_documentation_wizard.py +503 -0
  249. empathy_software_plugin/wizards/base_wizard.py +288 -0
  250. empathy_software_plugin/wizards/book_chapter_wizard.py +519 -0
  251. empathy_software_plugin/wizards/code_review_wizard.py +606 -0
  252. empathy_software_plugin/wizards/debugging/__init__.py +50 -0
  253. empathy_software_plugin/wizards/debugging/bug_risk_analyzer.py +414 -0
  254. empathy_software_plugin/wizards/debugging/config_loaders.py +442 -0
  255. empathy_software_plugin/wizards/debugging/fix_applier.py +469 -0
  256. empathy_software_plugin/wizards/debugging/language_patterns.py +383 -0
  257. empathy_software_plugin/wizards/debugging/linter_parsers.py +470 -0
  258. empathy_software_plugin/wizards/debugging/verification.py +369 -0
  259. empathy_software_plugin/wizards/enhanced_testing_wizard.py +537 -0
  260. empathy_software_plugin/wizards/memory_enhanced_debugging_wizard.py +816 -0
  261. empathy_software_plugin/wizards/multi_model_wizard.py +501 -0
  262. empathy_software_plugin/wizards/pattern_extraction_wizard.py +422 -0
  263. empathy_software_plugin/wizards/pattern_retriever_wizard.py +400 -0
  264. empathy_software_plugin/wizards/performance/__init__.py +9 -0
  265. empathy_software_plugin/wizards/performance/bottleneck_detector.py +221 -0
  266. empathy_software_plugin/wizards/performance/profiler_parsers.py +278 -0
  267. empathy_software_plugin/wizards/performance/trajectory_analyzer.py +429 -0
  268. empathy_software_plugin/wizards/performance_profiling_wizard.py +305 -0
  269. empathy_software_plugin/wizards/prompt_engineering_wizard.py +425 -0
  270. empathy_software_plugin/wizards/rag_pattern_wizard.py +461 -0
  271. empathy_software_plugin/wizards/security/__init__.py +32 -0
  272. empathy_software_plugin/wizards/security/exploit_analyzer.py +290 -0
  273. empathy_software_plugin/wizards/security/owasp_patterns.py +241 -0
  274. empathy_software_plugin/wizards/security/vulnerability_scanner.py +604 -0
  275. empathy_software_plugin/wizards/security_analysis_wizard.py +322 -0
  276. empathy_software_plugin/wizards/security_learning_wizard.py +740 -0
  277. empathy_software_plugin/wizards/tech_debt_wizard.py +726 -0
  278. empathy_software_plugin/wizards/testing/__init__.py +27 -0
  279. empathy_software_plugin/wizards/testing/coverage_analyzer.py +459 -0
  280. empathy_software_plugin/wizards/testing/quality_analyzer.py +531 -0
  281. empathy_software_plugin/wizards/testing/test_suggester.py +533 -0
  282. empathy_software_plugin/wizards/testing_wizard.py +274 -0
  283. hot_reload/README.md +473 -0
  284. hot_reload/__init__.py +62 -0
  285. hot_reload/config.py +84 -0
  286. hot_reload/integration.py +228 -0
  287. hot_reload/reloader.py +298 -0
  288. hot_reload/watcher.py +179 -0
  289. hot_reload/websocket.py +176 -0
  290. scaffolding/README.md +589 -0
  291. scaffolding/__init__.py +35 -0
  292. scaffolding/__main__.py +14 -0
  293. scaffolding/cli.py +240 -0
  294. test_generator/__init__.py +38 -0
  295. test_generator/__main__.py +14 -0
  296. test_generator/cli.py +226 -0
  297. test_generator/generator.py +325 -0
  298. test_generator/risk_analyzer.py +216 -0
  299. workflow_patterns/__init__.py +33 -0
  300. workflow_patterns/behavior.py +249 -0
  301. workflow_patterns/core.py +76 -0
  302. workflow_patterns/output.py +99 -0
  303. workflow_patterns/registry.py +255 -0
  304. workflow_patterns/structural.py +288 -0
  305. workflow_scaffolding/__init__.py +11 -0
  306. workflow_scaffolding/__main__.py +12 -0
  307. workflow_scaffolding/cli.py +206 -0
  308. workflow_scaffolding/generator.py +265 -0
  309. agents/code_inspection/patterns/inspection/recurring_B112.json +0 -18
  310. agents/code_inspection/patterns/inspection/recurring_F541.json +0 -16
  311. agents/code_inspection/patterns/inspection/recurring_FORMAT.json +0 -25
  312. agents/code_inspection/patterns/inspection/recurring_bug_20250822_def456.json +0 -16
  313. agents/code_inspection/patterns/inspection/recurring_bug_20250915_abc123.json +0 -16
  314. agents/code_inspection/patterns/inspection/recurring_bug_20251212_3c5b9951.json +0 -16
  315. agents/code_inspection/patterns/inspection/recurring_bug_20251212_97c0f72f.json +0 -16
  316. agents/code_inspection/patterns/inspection/recurring_bug_20251212_a0871d53.json +0 -16
  317. agents/code_inspection/patterns/inspection/recurring_bug_20251212_a9b6ec41.json +0 -16
  318. agents/code_inspection/patterns/inspection/recurring_bug_null_001.json +0 -16
  319. agents/code_inspection/patterns/inspection/recurring_builtin.json +0 -16
  320. agents/compliance_anticipation_agent.py +0 -1427
  321. agents/epic_integration_wizard.py +0 -541
  322. agents/trust_building_behaviors.py +0 -891
  323. empathy_framework-3.2.3.dist-info/RECORD +0 -104
  324. empathy_framework-3.2.3.dist-info/entry_points.txt +0 -7
  325. empathy_llm_toolkit/htmlcov/status.json +0 -1
  326. empathy_llm_toolkit/security/htmlcov/status.json +0 -1
  327. {empathy_framework-3.2.3.dist-info → empathy_framework-3.8.2.dist-info}/WHEEL +0 -0
  328. {empathy_framework-3.2.3.dist-info → empathy_framework-3.8.2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,253 @@
1
+ """Dependency manager for cache optional dependencies.
2
+
3
+ Handles auto-detection, user prompts, and installation of sentence-transformers.
4
+
5
+ Copyright 2025 Smart-AI-Memory
6
+ Licensed under Fair Source License 0.9
7
+ """
8
+
9
+ import logging
10
+ import subprocess
11
+ import sys
12
+ from pathlib import Path
13
+ from typing import Any
14
+
15
+ import yaml
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+
20
+ class DependencyManager:
21
+ """Manage optional cache dependencies with user prompts.
22
+
23
+ Handles:
24
+ - Auto-detection of installed dependencies
25
+ - One-time user prompt to install cache deps
26
+ - Configuration persistence (user preferences)
27
+ - Pip-based installation
28
+
29
+ Example:
30
+ manager = DependencyManager()
31
+
32
+ if manager.should_prompt_cache_install():
33
+ manager.prompt_cache_install()
34
+
35
+ """
36
+
37
+ def __init__(self, config_path: Path | None = None):
38
+ """Initialize dependency manager.
39
+
40
+ Args:
41
+ config_path: Path to config file (default: ~/.empathy/config.yml).
42
+
43
+ """
44
+ self.config_path = config_path or Path.home() / ".empathy" / "config.yml"
45
+ self.config = self._load_config()
46
+
47
+ def _load_config(self) -> dict:
48
+ """Load user configuration.
49
+
50
+ Returns:
51
+ Configuration dictionary.
52
+
53
+ """
54
+ if not self.config_path.exists():
55
+ return {}
56
+
57
+ try:
58
+ with open(self.config_path) as f:
59
+ return yaml.safe_load(f) or {}
60
+ except (yaml.YAMLError, OSError) as e:
61
+ logger.warning(f"Failed to load config: {e}")
62
+ return {}
63
+
64
+ def _save_config(self) -> None:
65
+ """Save configuration to disk."""
66
+ try:
67
+ self.config_path.parent.mkdir(parents=True, exist_ok=True)
68
+ with open(self.config_path, "w") as f:
69
+ yaml.safe_dump(self.config, f, default_flow_style=False)
70
+ except (yaml.YAMLError, OSError) as e:
71
+ logger.error(f"Failed to save config: {e}")
72
+
73
+ def is_cache_installed(self) -> bool:
74
+ """Check if cache dependencies are installed.
75
+
76
+ Returns:
77
+ True if sentence-transformers is available, False otherwise.
78
+
79
+ """
80
+ try:
81
+ import sentence_transformers # noqa: F401
82
+ import torch # noqa: F401
83
+
84
+ return True
85
+ except ImportError:
86
+ return False
87
+
88
+ def should_prompt_cache_install(self) -> bool:
89
+ """Check if we should prompt user to install cache.
90
+
91
+ Returns:
92
+ True if we should prompt, False otherwise.
93
+
94
+ """
95
+ # Never prompt if already installed
96
+ if self.is_cache_installed():
97
+ return False
98
+
99
+ # Never prompt if user already declined
100
+ cache_config = self.config.get("cache", {})
101
+ if cache_config.get("install_declined", False):
102
+ return False
103
+
104
+ # Never prompt if prompt already shown
105
+ if cache_config.get("prompt_shown", False):
106
+ return False
107
+
108
+ # Never prompt if user disabled prompts
109
+ if not cache_config.get("prompt_enabled", True):
110
+ return False
111
+
112
+ # Prompt on first run
113
+ return True
114
+
115
+ def prompt_cache_install(self) -> bool:
116
+ """Prompt user to install cache dependencies.
117
+
118
+ Returns:
119
+ True if user accepted and install succeeded, False otherwise.
120
+
121
+ """
122
+ print("\n" + "=" * 60)
123
+ print("⚡ Smart Caching Available")
124
+ print("=" * 60)
125
+ print()
126
+ print(" Empathy Framework can reduce your API costs by 70% with hybrid caching.")
127
+ print(" This requires installing sentence-transformers (~150MB).")
128
+ print()
129
+
130
+ try:
131
+ response = (
132
+ input(" Would you like to enable smart caching now? [Y/n]: ").strip().lower()
133
+ )
134
+ except (EOFError, KeyboardInterrupt):
135
+ print("\n Skipping cache installation.")
136
+ response = "n"
137
+
138
+ if response in ["y", "yes", ""]:
139
+ return self.install_cache_dependencies()
140
+ else:
141
+ print()
142
+ print(" ℹ Using hash-only cache (30% savings)")
143
+ print(" ℹ To enable later: empathy install cache")
144
+ print()
145
+ print("=" * 60)
146
+ print()
147
+
148
+ # Save that user declined
149
+ if "cache" not in self.config:
150
+ self.config["cache"] = {}
151
+ self.config["cache"]["install_declined"] = True
152
+ self.config["cache"]["prompt_shown"] = True
153
+ self._save_config()
154
+
155
+ return False
156
+
157
+ def install_cache_dependencies(self) -> bool:
158
+ """Install cache dependencies using pip.
159
+
160
+ Returns:
161
+ True if installation succeeded, False otherwise.
162
+
163
+ """
164
+ print()
165
+ print(" ↓ Installing cache dependencies...")
166
+ print()
167
+
168
+ packages = [
169
+ "sentence-transformers>=2.0.0",
170
+ "torch>=2.0.0",
171
+ "numpy>=1.24.0",
172
+ ]
173
+
174
+ try:
175
+ # Run pip install
176
+ subprocess.check_call(
177
+ [sys.executable, "-m", "pip", "install", "--quiet"] + packages,
178
+ stdout=subprocess.PIPE,
179
+ stderr=subprocess.PIPE,
180
+ )
181
+
182
+ print(" ✓ sentence-transformers installed")
183
+ print(" ✓ torch installed")
184
+ print(" ✓ numpy installed")
185
+ print()
186
+ print(" ✓ Smart caching enabled! Future runs will save 70% on costs.")
187
+ print()
188
+ print("=" * 60)
189
+ print()
190
+
191
+ # Mark as installed in config
192
+ if "cache" not in self.config:
193
+ self.config["cache"] = {}
194
+ self.config["cache"]["enabled"] = True
195
+ self.config["cache"]["install_declined"] = False
196
+ self.config["cache"]["prompt_shown"] = True
197
+ self._save_config()
198
+
199
+ return True
200
+
201
+ except subprocess.CalledProcessError as e:
202
+ print()
203
+ print(f" ✗ Installation failed: {e}")
204
+ print(" ℹ You can try manually: pip install empathy-framework[cache]")
205
+ print()
206
+ print("=" * 60)
207
+ print()
208
+
209
+ logger.error(f"Failed to install cache dependencies: {e}")
210
+ return False
211
+
212
+ def disable_prompts(self) -> None:
213
+ """Disable cache installation prompts."""
214
+ if "cache" not in self.config:
215
+ self.config["cache"] = {}
216
+ self.config["cache"]["prompt_enabled"] = False
217
+ self._save_config()
218
+ logger.info("Cache installation prompts disabled")
219
+
220
+ def enable_prompts(self) -> None:
221
+ """Re-enable cache installation prompts."""
222
+ if "cache" not in self.config:
223
+ self.config["cache"] = {}
224
+ self.config["cache"]["prompt_enabled"] = True
225
+ self.config["cache"]["prompt_shown"] = False
226
+ self.config["cache"]["install_declined"] = False
227
+ self._save_config()
228
+ logger.info("Cache installation prompts re-enabled")
229
+
230
+ def get_config(self) -> dict[str, Any]:
231
+ """Get cache configuration.
232
+
233
+ Returns:
234
+ Cache configuration dictionary.
235
+
236
+ """
237
+ result = self.config.get("cache", {})
238
+ if not isinstance(result, dict):
239
+ return {}
240
+ return result
241
+
242
+ def set_config(self, key: str, value: Any) -> None:
243
+ """Set cache configuration value.
244
+
245
+ Args:
246
+ key: Configuration key.
247
+ value: Configuration value.
248
+
249
+ """
250
+ if "cache" not in self.config:
251
+ self.config["cache"] = {}
252
+ self.config["cache"][key] = value
253
+ self._save_config()
@@ -0,0 +1,248 @@
1
+ """Hash-only cache implementation using SHA256 for exact matching.
2
+
3
+ Provides fast exact-match caching with ~30% hit rate. No dependencies required.
4
+
5
+ Copyright 2025 Smart-AI-Memory
6
+ Licensed under Fair Source License 0.9
7
+ """
8
+
9
+ import logging
10
+ import time
11
+ from typing import Any
12
+
13
+ from .base import BaseCache, CacheEntry, CacheStats
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ class HashOnlyCache(BaseCache):
19
+ """Fast hash-based cache for exact prompt matches.
20
+
21
+ Uses SHA256 hashing for O(1) lookup. Provides ~30% cache hit rate
22
+ for workflows with repeated exact prompts (e.g., re-reviewing same code).
23
+
24
+ No external dependencies required - always available as fallback.
25
+
26
+ Example:
27
+ cache = HashOnlyCache()
28
+
29
+ # First call (miss)
30
+ result = cache.get("code-review", "scan", prompt, "claude-3-5-sonnet")
31
+ # → None
32
+
33
+ # Store response
34
+ cache.put("code-review", "scan", prompt, "claude-3-5-sonnet", response)
35
+
36
+ # Second call with exact same prompt (hit)
37
+ result = cache.get("code-review", "scan", prompt, "claude-3-5-sonnet")
38
+ # → response (from cache, <5μs lookup)
39
+
40
+ """
41
+
42
+ def __init__(
43
+ self,
44
+ max_size_mb: int = 500,
45
+ default_ttl: int = 86400,
46
+ max_memory_mb: int = 100,
47
+ ):
48
+ """Initialize hash-only cache.
49
+
50
+ Args:
51
+ max_size_mb: Maximum disk cache size in MB.
52
+ default_ttl: Default TTL in seconds (24 hours).
53
+ max_memory_mb: Maximum in-memory cache size in MB.
54
+
55
+ """
56
+ super().__init__(max_size_mb, default_ttl)
57
+ self.max_memory_mb = max_memory_mb
58
+ self._memory_cache: dict[str, CacheEntry] = {}
59
+ self._access_times: dict[str, float] = {} # For LRU eviction
60
+
61
+ logger.debug(
62
+ f"HashOnlyCache initialized (max_memory: {max_memory_mb}MB, "
63
+ f"max_disk: {max_size_mb}MB, ttl: {default_ttl}s)"
64
+ )
65
+
66
+ def get(
67
+ self,
68
+ workflow: str,
69
+ stage: str,
70
+ prompt: str,
71
+ model: str,
72
+ ) -> Any | None:
73
+ """Get cached response for exact prompt match.
74
+
75
+ Args:
76
+ workflow: Workflow name (e.g., "code-review").
77
+ stage: Stage name (e.g., "scan").
78
+ prompt: Exact prompt text.
79
+ model: Model identifier.
80
+
81
+ Returns:
82
+ Cached response if exact match found and not expired, None otherwise.
83
+
84
+ """
85
+ cache_key = self._create_cache_key(workflow, stage, prompt, model)
86
+
87
+ # Check in-memory cache
88
+ if cache_key in self._memory_cache:
89
+ entry = self._memory_cache[cache_key]
90
+
91
+ # Check if expired
92
+ current_time = time.time()
93
+ if entry.is_expired(current_time):
94
+ logger.debug(f"Cache entry expired: {cache_key[:16]}...")
95
+ self._evict_entry(cache_key)
96
+ self.stats.misses += 1
97
+ return None
98
+
99
+ # Cache hit!
100
+ self._access_times[cache_key] = current_time
101
+ self.stats.hits += 1
102
+ logger.debug(
103
+ f"Cache HIT (hash): {workflow}/{stage} "
104
+ f"(key: {cache_key[:16]}..., hit_rate: {self.stats.hit_rate:.1f}%)"
105
+ )
106
+ return entry.response
107
+
108
+ # Cache miss
109
+ self.stats.misses += 1
110
+ logger.debug(
111
+ f"Cache MISS (hash): {workflow}/{stage} "
112
+ f"(key: {cache_key[:16]}..., hit_rate: {self.stats.hit_rate:.1f}%)"
113
+ )
114
+ return None
115
+
116
+ def put(
117
+ self,
118
+ workflow: str,
119
+ stage: str,
120
+ prompt: str,
121
+ model: str,
122
+ response: Any,
123
+ ttl: int | None = None,
124
+ ) -> None:
125
+ """Store response in cache.
126
+
127
+ Args:
128
+ workflow: Workflow name.
129
+ stage: Stage name.
130
+ prompt: Prompt text.
131
+ model: Model identifier.
132
+ response: LLM response to cache.
133
+ ttl: Optional custom TTL (uses default if None).
134
+
135
+ """
136
+ cache_key = self._create_cache_key(workflow, stage, prompt, model)
137
+ prompt_hash = self._create_cache_key("", "", prompt, "") # Hash of prompt only
138
+
139
+ # Create cache entry
140
+ entry = CacheEntry(
141
+ key=cache_key,
142
+ response=response,
143
+ workflow=workflow,
144
+ stage=stage,
145
+ model=model,
146
+ prompt_hash=prompt_hash,
147
+ timestamp=time.time(),
148
+ ttl=ttl or self.default_ttl,
149
+ )
150
+
151
+ # Check if we need to evict entries
152
+ self._maybe_evict_lru()
153
+
154
+ # Store in memory
155
+ self._memory_cache[cache_key] = entry
156
+ self._access_times[cache_key] = entry.timestamp
157
+
158
+ logger.debug(
159
+ f"Cache PUT: {workflow}/{stage} (key: {cache_key[:16]}..., "
160
+ f"entries: {len(self._memory_cache)})"
161
+ )
162
+
163
+ def clear(self) -> None:
164
+ """Clear all cached entries."""
165
+ count = len(self._memory_cache)
166
+ self._memory_cache.clear()
167
+ self._access_times.clear()
168
+ logger.info(f"Cache cleared ({count} entries removed)")
169
+
170
+ def get_stats(self) -> CacheStats:
171
+ """Get cache statistics.
172
+
173
+ Returns:
174
+ CacheStats with hit/miss/eviction counts.
175
+
176
+ """
177
+ return self.stats
178
+
179
+ def _evict_entry(self, cache_key: str) -> None:
180
+ """Remove entry from cache.
181
+
182
+ Args:
183
+ cache_key: Key to evict.
184
+
185
+ """
186
+ if cache_key in self._memory_cache:
187
+ del self._memory_cache[cache_key]
188
+ if cache_key in self._access_times:
189
+ del self._access_times[cache_key]
190
+ self.stats.evictions += 1
191
+
192
+ def _maybe_evict_lru(self) -> None:
193
+ """Evict least recently used entries if cache is too large.
194
+
195
+ Uses LRU (Least Recently Used) eviction policy.
196
+
197
+ """
198
+ # Estimate memory usage (rough)
199
+ estimated_mb = len(self._memory_cache) * 0.01 # Rough estimate: 10KB per entry
200
+
201
+ if estimated_mb > self.max_memory_mb:
202
+ # Evict 10% of entries (LRU)
203
+ num_to_evict = max(1, len(self._memory_cache) // 10)
204
+
205
+ # Sort by access time (oldest first)
206
+ sorted_keys = sorted(self._access_times.items(), key=lambda x: x[1])
207
+
208
+ for cache_key, _ in sorted_keys[:num_to_evict]:
209
+ self._evict_entry(cache_key)
210
+ logger.debug(f"LRU eviction: {cache_key[:16]}...")
211
+
212
+ logger.info(
213
+ f"LRU eviction: removed {num_to_evict} entries "
214
+ f"(cache size: {len(self._memory_cache)} entries)"
215
+ )
216
+
217
+ def evict_expired(self) -> int:
218
+ """Remove all expired entries.
219
+
220
+ Returns:
221
+ Number of entries evicted.
222
+
223
+ """
224
+ current_time = time.time()
225
+ expired_keys = [
226
+ key for key, entry in self._memory_cache.items() if entry.is_expired(current_time)
227
+ ]
228
+
229
+ for key in expired_keys:
230
+ self._evict_entry(key)
231
+
232
+ if expired_keys:
233
+ logger.info(f"Expired eviction: removed {len(expired_keys)} entries")
234
+
235
+ return len(expired_keys)
236
+
237
+ def size_info(self) -> dict[str, Any]:
238
+ """Get cache size information.
239
+
240
+ Returns:
241
+ Dictionary with cache size metrics.
242
+
243
+ """
244
+ return {
245
+ "entries": len(self._memory_cache),
246
+ "estimated_mb": len(self._memory_cache) * 0.01,
247
+ "max_memory_mb": self.max_memory_mb,
248
+ }