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.
- coach_wizards/__init__.py +11 -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 +22 -25
- 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.2.3.dist-info → empathy_framework-3.8.2.dist-info}/METADATA +513 -58
- empathy_framework-3.8.2.dist-info/RECORD +333 -0
- empathy_framework-3.8.2.dist-info/entry_points.txt +22 -0
- {empathy_framework-3.2.3.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 +177 -22
- 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 +51 -49
- empathy_llm_toolkit/git_pattern_extractor.py +16 -12
- 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 +13 -11
- 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 +18 -20
- empathy_llm_toolkit/state.py +20 -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 +76 -77
- empathy_os/adaptive/__init__.py +13 -0
- empathy_os/adaptive/task_complexity.py +127 -0
- empathy_os/{monitoring.py → agent_monitoring.py} +27 -27
- 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 +515 -109
- empathy_os/cli_unified.py +189 -42
- empathy_os/config/__init__.py +63 -0
- empathy_os/config/xml_config.py +239 -0
- empathy_os/config.py +87 -36
- empathy_os/coordination.py +48 -54
- empathy_os/core.py +90 -99
- empathy_os/cost_tracker.py +20 -23
- empathy_os/dashboard/__init__.py +15 -0
- empathy_os/dashboard/server.py +743 -0
- empathy_os/discovery.py +9 -11
- empathy_os/emergence.py +20 -21
- empathy_os/exceptions.py +18 -30
- empathy_os/feedback_loops.py +27 -30
- empathy_os/levels.py +31 -34
- empathy_os/leverage_points.py +27 -28
- empathy_os/logging_config.py +11 -12
- 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 +29 -28
- empathy_os/persistence.py +30 -34
- 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 +53 -56
- 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 +12 -11
- empathy_os/trust/__init__.py +28 -0
- empathy_os/trust/circuit_breaker.py +579 -0
- empathy_os/trust_building.py +44 -36
- 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} +123 -31
- 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 +35 -26
- 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-3.2.3.dist-info/RECORD +0 -104
- empathy_framework-3.2.3.dist-info/entry_points.txt +0 -7
- empathy_llm_toolkit/htmlcov/status.json +0 -1
- empathy_llm_toolkit/security/htmlcov/status.json +0 -1
- {empathy_framework-3.2.3.dist-info → empathy_framework-3.8.2.dist-info}/WHEEL +0 -0
- {empathy_framework-3.2.3.dist-info → empathy_framework-3.8.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,619 @@
|
|
|
1
|
+
"""Unified Memory Interface for Empathy Framework
|
|
2
|
+
|
|
3
|
+
Provides a single API for both short-term (Redis) and long-term (persistent) memory,
|
|
4
|
+
with automatic pattern promotion and environment-aware storage backend selection.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
from empathy_os.memory import UnifiedMemory
|
|
8
|
+
|
|
9
|
+
memory = UnifiedMemory(
|
|
10
|
+
user_id="agent@company.com",
|
|
11
|
+
environment="production", # or "staging", "development"
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
# Short-term operations
|
|
15
|
+
memory.stash("working_data", {"key": "value"})
|
|
16
|
+
data = memory.retrieve("working_data")
|
|
17
|
+
|
|
18
|
+
# Long-term operations
|
|
19
|
+
result = memory.persist_pattern(content, pattern_type="algorithm")
|
|
20
|
+
pattern = memory.recall_pattern(pattern_id)
|
|
21
|
+
|
|
22
|
+
# Pattern promotion
|
|
23
|
+
memory.promote_pattern(staged_pattern_id)
|
|
24
|
+
|
|
25
|
+
Copyright 2025 Smart AI Memory, LLC
|
|
26
|
+
Licensed under Fair Source 0.9
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
import os
|
|
30
|
+
import uuid
|
|
31
|
+
from dataclasses import dataclass, field
|
|
32
|
+
from datetime import datetime
|
|
33
|
+
from enum import Enum
|
|
34
|
+
from typing import Any
|
|
35
|
+
|
|
36
|
+
import structlog
|
|
37
|
+
|
|
38
|
+
from .claude_memory import ClaudeMemoryConfig
|
|
39
|
+
from .config import get_redis_memory
|
|
40
|
+
from .long_term import Classification, SecureMemDocsIntegration
|
|
41
|
+
from .redis_bootstrap import RedisStartMethod, RedisStatus, ensure_redis
|
|
42
|
+
from .short_term import (
|
|
43
|
+
AccessTier,
|
|
44
|
+
AgentCredentials,
|
|
45
|
+
RedisShortTermMemory,
|
|
46
|
+
StagedPattern,
|
|
47
|
+
TTLStrategy,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
logger = structlog.get_logger(__name__)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class Environment(Enum):
|
|
54
|
+
"""Deployment environment for storage configuration."""
|
|
55
|
+
|
|
56
|
+
DEVELOPMENT = "development"
|
|
57
|
+
STAGING = "staging"
|
|
58
|
+
PRODUCTION = "production"
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@dataclass
|
|
62
|
+
class MemoryConfig:
|
|
63
|
+
"""Configuration for unified memory system."""
|
|
64
|
+
|
|
65
|
+
# Environment
|
|
66
|
+
environment: Environment = Environment.DEVELOPMENT
|
|
67
|
+
|
|
68
|
+
# Short-term memory settings
|
|
69
|
+
redis_url: str | None = None
|
|
70
|
+
redis_host: str = "localhost"
|
|
71
|
+
redis_port: int = 6379
|
|
72
|
+
redis_mock: bool = False
|
|
73
|
+
redis_auto_start: bool = True # Auto-start Redis if not running
|
|
74
|
+
default_ttl_seconds: int = 3600 # 1 hour
|
|
75
|
+
|
|
76
|
+
# Long-term memory settings
|
|
77
|
+
storage_dir: str = "./memdocs_storage"
|
|
78
|
+
encryption_enabled: bool = True
|
|
79
|
+
|
|
80
|
+
# Claude memory settings
|
|
81
|
+
claude_memory_enabled: bool = True
|
|
82
|
+
load_enterprise_memory: bool = True
|
|
83
|
+
load_project_memory: bool = True
|
|
84
|
+
load_user_memory: bool = True
|
|
85
|
+
|
|
86
|
+
# Pattern promotion settings
|
|
87
|
+
auto_promote_threshold: float = 0.8 # Confidence threshold for auto-promotion
|
|
88
|
+
|
|
89
|
+
@classmethod
|
|
90
|
+
def from_environment(cls) -> "MemoryConfig":
|
|
91
|
+
"""Create configuration from environment variables.
|
|
92
|
+
|
|
93
|
+
Environment Variables:
|
|
94
|
+
EMPATHY_ENV: Environment (development/staging/production)
|
|
95
|
+
REDIS_URL: Redis connection URL
|
|
96
|
+
EMPATHY_REDIS_MOCK: Use mock Redis (true/false)
|
|
97
|
+
EMPATHY_STORAGE_DIR: Long-term storage directory
|
|
98
|
+
EMPATHY_ENCRYPTION: Enable encryption (true/false)
|
|
99
|
+
"""
|
|
100
|
+
env_str = os.getenv("EMPATHY_ENV", "development").lower()
|
|
101
|
+
environment = (
|
|
102
|
+
Environment(env_str)
|
|
103
|
+
if env_str in [e.value for e in Environment]
|
|
104
|
+
else Environment.DEVELOPMENT
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
return cls(
|
|
108
|
+
environment=environment,
|
|
109
|
+
redis_url=os.getenv("REDIS_URL"),
|
|
110
|
+
redis_host=os.getenv("EMPATHY_REDIS_HOST", "localhost"),
|
|
111
|
+
redis_port=int(os.getenv("EMPATHY_REDIS_PORT", "6379")),
|
|
112
|
+
redis_mock=os.getenv("EMPATHY_REDIS_MOCK", "").lower() == "true",
|
|
113
|
+
redis_auto_start=os.getenv("EMPATHY_REDIS_AUTO_START", "true").lower() == "true",
|
|
114
|
+
storage_dir=os.getenv("EMPATHY_STORAGE_DIR", "./memdocs_storage"),
|
|
115
|
+
encryption_enabled=os.getenv("EMPATHY_ENCRYPTION", "true").lower() == "true",
|
|
116
|
+
claude_memory_enabled=os.getenv("EMPATHY_CLAUDE_MEMORY", "true").lower() == "true",
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@dataclass
|
|
121
|
+
class UnifiedMemory:
|
|
122
|
+
"""Unified interface for short-term and long-term memory.
|
|
123
|
+
|
|
124
|
+
Provides:
|
|
125
|
+
- Short-term memory (Redis): Fast, TTL-based working memory
|
|
126
|
+
- Long-term memory (Persistent): Cross-session pattern storage
|
|
127
|
+
- Pattern promotion: Move validated patterns from short to long-term
|
|
128
|
+
- Environment-aware configuration: Auto-detect storage backends
|
|
129
|
+
"""
|
|
130
|
+
|
|
131
|
+
user_id: str
|
|
132
|
+
config: MemoryConfig = field(default_factory=MemoryConfig.from_environment)
|
|
133
|
+
access_tier: AccessTier = AccessTier.CONTRIBUTOR
|
|
134
|
+
|
|
135
|
+
# Internal state
|
|
136
|
+
_short_term: RedisShortTermMemory | None = field(default=None, init=False)
|
|
137
|
+
_long_term: SecureMemDocsIntegration | None = field(default=None, init=False)
|
|
138
|
+
_redis_status: RedisStatus | None = field(default=None, init=False)
|
|
139
|
+
_initialized: bool = field(default=False, init=False)
|
|
140
|
+
|
|
141
|
+
def __post_init__(self):
|
|
142
|
+
"""Initialize memory backends based on configuration."""
|
|
143
|
+
self._initialize_backends()
|
|
144
|
+
|
|
145
|
+
def _initialize_backends(self):
|
|
146
|
+
"""Initialize short-term and long-term memory backends."""
|
|
147
|
+
if self._initialized:
|
|
148
|
+
return
|
|
149
|
+
|
|
150
|
+
# Initialize short-term memory (Redis)
|
|
151
|
+
try:
|
|
152
|
+
if self.config.redis_mock:
|
|
153
|
+
self._short_term = RedisShortTermMemory(use_mock=True)
|
|
154
|
+
self._redis_status = RedisStatus(
|
|
155
|
+
available=False,
|
|
156
|
+
method=RedisStartMethod.MOCK,
|
|
157
|
+
message="Mock mode explicitly enabled",
|
|
158
|
+
)
|
|
159
|
+
elif self.config.redis_url:
|
|
160
|
+
self._short_term = get_redis_memory(url=self.config.redis_url)
|
|
161
|
+
self._redis_status = RedisStatus(
|
|
162
|
+
available=True,
|
|
163
|
+
method=RedisStartMethod.ALREADY_RUNNING,
|
|
164
|
+
message="Connected via REDIS_URL",
|
|
165
|
+
)
|
|
166
|
+
# Use auto-start if enabled
|
|
167
|
+
elif self.config.redis_auto_start:
|
|
168
|
+
self._redis_status = ensure_redis(
|
|
169
|
+
host=self.config.redis_host,
|
|
170
|
+
port=self.config.redis_port,
|
|
171
|
+
auto_start=True,
|
|
172
|
+
verbose=True,
|
|
173
|
+
)
|
|
174
|
+
if self._redis_status.available:
|
|
175
|
+
self._short_term = RedisShortTermMemory(
|
|
176
|
+
host=self.config.redis_host,
|
|
177
|
+
port=self.config.redis_port,
|
|
178
|
+
use_mock=False,
|
|
179
|
+
)
|
|
180
|
+
else:
|
|
181
|
+
self._short_term = RedisShortTermMemory(use_mock=True)
|
|
182
|
+
else:
|
|
183
|
+
self._short_term = get_redis_memory()
|
|
184
|
+
self._redis_status = RedisStatus(
|
|
185
|
+
available=True,
|
|
186
|
+
method=RedisStartMethod.ALREADY_RUNNING,
|
|
187
|
+
message="Connected to existing Redis",
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
logger.info(
|
|
191
|
+
"short_term_memory_initialized",
|
|
192
|
+
mock_mode=self.config.redis_mock or not self._redis_status.available,
|
|
193
|
+
redis_method=self._redis_status.method.value if self._redis_status else "unknown",
|
|
194
|
+
environment=self.config.environment.value,
|
|
195
|
+
)
|
|
196
|
+
except Exception as e:
|
|
197
|
+
logger.warning("short_term_memory_failed", error=str(e))
|
|
198
|
+
self._short_term = RedisShortTermMemory(use_mock=True)
|
|
199
|
+
self._redis_status = RedisStatus(
|
|
200
|
+
available=False,
|
|
201
|
+
method=RedisStartMethod.MOCK,
|
|
202
|
+
message=f"Failed to initialize: {e}",
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
# Initialize long-term memory (SecureMemDocs)
|
|
206
|
+
try:
|
|
207
|
+
claude_config = ClaudeMemoryConfig(
|
|
208
|
+
enabled=self.config.claude_memory_enabled,
|
|
209
|
+
load_enterprise=self.config.load_enterprise_memory,
|
|
210
|
+
load_project=self.config.load_project_memory,
|
|
211
|
+
load_user=self.config.load_user_memory,
|
|
212
|
+
)
|
|
213
|
+
self._long_term = SecureMemDocsIntegration(
|
|
214
|
+
claude_memory_config=claude_config,
|
|
215
|
+
storage_dir=self.config.storage_dir,
|
|
216
|
+
enable_encryption=self.config.encryption_enabled,
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
logger.info(
|
|
220
|
+
"long_term_memory_initialized",
|
|
221
|
+
storage_dir=self.config.storage_dir,
|
|
222
|
+
encryption=self.config.encryption_enabled,
|
|
223
|
+
)
|
|
224
|
+
except Exception as e:
|
|
225
|
+
logger.error("long_term_memory_failed", error=str(e))
|
|
226
|
+
self._long_term = None
|
|
227
|
+
|
|
228
|
+
self._initialized = True
|
|
229
|
+
|
|
230
|
+
@property
|
|
231
|
+
def credentials(self) -> AgentCredentials:
|
|
232
|
+
"""Get agent credentials for short-term memory operations."""
|
|
233
|
+
return AgentCredentials(agent_id=self.user_id, tier=self.access_tier)
|
|
234
|
+
|
|
235
|
+
def get_backend_status(self) -> dict[str, Any]:
|
|
236
|
+
"""Get the current status of all memory backends.
|
|
237
|
+
|
|
238
|
+
Returns a structured dict suitable for health checks, debugging,
|
|
239
|
+
and dashboard display. Can be serialized to JSON.
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
dict with keys:
|
|
243
|
+
- environment: Current environment (development/staging/production)
|
|
244
|
+
- short_term: Status of Redis-based short-term memory
|
|
245
|
+
- long_term: Status of persistent long-term memory
|
|
246
|
+
- initialized: Whether backends have been initialized
|
|
247
|
+
|
|
248
|
+
Example:
|
|
249
|
+
>>> memory = UnifiedMemory(user_id="agent")
|
|
250
|
+
>>> status = memory.get_backend_status()
|
|
251
|
+
>>> print(status["short_term"]["available"])
|
|
252
|
+
True
|
|
253
|
+
|
|
254
|
+
"""
|
|
255
|
+
short_term_status: dict[str, Any] = {
|
|
256
|
+
"available": False,
|
|
257
|
+
"mock": True,
|
|
258
|
+
"method": "unknown",
|
|
259
|
+
"message": "Not initialized",
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if self._redis_status:
|
|
263
|
+
short_term_status = {
|
|
264
|
+
"available": self._redis_status.available,
|
|
265
|
+
"mock": not self._redis_status.available
|
|
266
|
+
or self._redis_status.method == RedisStartMethod.MOCK,
|
|
267
|
+
"method": self._redis_status.method.value,
|
|
268
|
+
"message": self._redis_status.message,
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
long_term_status: dict[str, Any] = {
|
|
272
|
+
"available": self._long_term is not None,
|
|
273
|
+
"storage_dir": self.config.storage_dir,
|
|
274
|
+
"encryption_enabled": self.config.encryption_enabled,
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return {
|
|
278
|
+
"environment": self.config.environment.value,
|
|
279
|
+
"initialized": self._initialized,
|
|
280
|
+
"short_term": short_term_status,
|
|
281
|
+
"long_term": long_term_status,
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
# =========================================================================
|
|
285
|
+
# SHORT-TERM MEMORY OPERATIONS
|
|
286
|
+
# =========================================================================
|
|
287
|
+
|
|
288
|
+
def stash(self, key: str, value: Any, ttl_seconds: int | None = None) -> bool:
|
|
289
|
+
"""Store data in short-term memory with TTL.
|
|
290
|
+
|
|
291
|
+
Args:
|
|
292
|
+
key: Storage key
|
|
293
|
+
value: Data to store (must be JSON-serializable)
|
|
294
|
+
ttl_seconds: Time-to-live in seconds (default from config)
|
|
295
|
+
|
|
296
|
+
Returns:
|
|
297
|
+
True if stored successfully
|
|
298
|
+
|
|
299
|
+
"""
|
|
300
|
+
if not self._short_term:
|
|
301
|
+
logger.warning("short_term_memory_unavailable")
|
|
302
|
+
return False
|
|
303
|
+
|
|
304
|
+
# Map ttl_seconds to TTLStrategy (use WORKING_RESULTS as default)
|
|
305
|
+
ttl_strategy = TTLStrategy.WORKING_RESULTS
|
|
306
|
+
if ttl_seconds is not None:
|
|
307
|
+
# Find closest TTL strategy or use working results
|
|
308
|
+
if ttl_seconds <= TTLStrategy.COORDINATION.value:
|
|
309
|
+
ttl_strategy = TTLStrategy.COORDINATION
|
|
310
|
+
elif ttl_seconds <= TTLStrategy.SESSION.value:
|
|
311
|
+
ttl_strategy = TTLStrategy.SESSION
|
|
312
|
+
elif ttl_seconds <= TTLStrategy.WORKING_RESULTS.value:
|
|
313
|
+
ttl_strategy = TTLStrategy.WORKING_RESULTS
|
|
314
|
+
elif ttl_seconds <= TTLStrategy.STAGED_PATTERNS.value:
|
|
315
|
+
ttl_strategy = TTLStrategy.STAGED_PATTERNS
|
|
316
|
+
else:
|
|
317
|
+
ttl_strategy = TTLStrategy.CONFLICT_CONTEXT
|
|
318
|
+
|
|
319
|
+
return self._short_term.stash(key, value, self.credentials, ttl_strategy)
|
|
320
|
+
|
|
321
|
+
def retrieve(self, key: str) -> Any | None:
|
|
322
|
+
"""Retrieve data from short-term memory.
|
|
323
|
+
|
|
324
|
+
Args:
|
|
325
|
+
key: Storage key
|
|
326
|
+
|
|
327
|
+
Returns:
|
|
328
|
+
Stored data or None if not found
|
|
329
|
+
|
|
330
|
+
"""
|
|
331
|
+
if not self._short_term:
|
|
332
|
+
return None
|
|
333
|
+
|
|
334
|
+
return self._short_term.retrieve(key, self.credentials)
|
|
335
|
+
|
|
336
|
+
def stage_pattern(
|
|
337
|
+
self,
|
|
338
|
+
pattern_data: dict[str, Any],
|
|
339
|
+
pattern_type: str = "general",
|
|
340
|
+
ttl_hours: int = 24,
|
|
341
|
+
) -> str | None:
|
|
342
|
+
"""Stage a pattern for validation before long-term storage.
|
|
343
|
+
|
|
344
|
+
Args:
|
|
345
|
+
pattern_data: Pattern content and metadata
|
|
346
|
+
pattern_type: Type of pattern (algorithm, protocol, etc.)
|
|
347
|
+
ttl_hours: Hours before staged pattern expires (not used in current impl)
|
|
348
|
+
|
|
349
|
+
Returns:
|
|
350
|
+
Staged pattern ID or None if failed
|
|
351
|
+
|
|
352
|
+
"""
|
|
353
|
+
if not self._short_term:
|
|
354
|
+
logger.warning("short_term_memory_unavailable")
|
|
355
|
+
return None
|
|
356
|
+
|
|
357
|
+
# Create a StagedPattern object from the pattern_data dict
|
|
358
|
+
pattern_id = f"staged_{uuid.uuid4().hex[:12]}"
|
|
359
|
+
staged_pattern = StagedPattern(
|
|
360
|
+
pattern_id=pattern_id,
|
|
361
|
+
agent_id=self.user_id,
|
|
362
|
+
pattern_type=pattern_type,
|
|
363
|
+
name=pattern_data.get("name", f"Pattern {pattern_id[:8]}"),
|
|
364
|
+
description=pattern_data.get("description", ""),
|
|
365
|
+
code=pattern_data.get("code"),
|
|
366
|
+
context=pattern_data.get("context", {}),
|
|
367
|
+
confidence=pattern_data.get("confidence", 0.5),
|
|
368
|
+
staged_at=datetime.now(),
|
|
369
|
+
interests=pattern_data.get("interests", []),
|
|
370
|
+
)
|
|
371
|
+
# Store content in context if provided
|
|
372
|
+
if "content" in pattern_data:
|
|
373
|
+
staged_pattern.context["content"] = pattern_data["content"]
|
|
374
|
+
|
|
375
|
+
success = self._short_term.stage_pattern(staged_pattern, self.credentials)
|
|
376
|
+
return pattern_id if success else None
|
|
377
|
+
|
|
378
|
+
def get_staged_patterns(self) -> list[dict]:
|
|
379
|
+
"""Get all staged patterns awaiting validation.
|
|
380
|
+
|
|
381
|
+
Returns:
|
|
382
|
+
List of staged patterns with metadata
|
|
383
|
+
|
|
384
|
+
"""
|
|
385
|
+
if not self._short_term:
|
|
386
|
+
return []
|
|
387
|
+
|
|
388
|
+
staged_list = self._short_term.list_staged_patterns(self.credentials)
|
|
389
|
+
return [p.to_dict() for p in staged_list]
|
|
390
|
+
|
|
391
|
+
# =========================================================================
|
|
392
|
+
# LONG-TERM MEMORY OPERATIONS
|
|
393
|
+
# =========================================================================
|
|
394
|
+
|
|
395
|
+
def persist_pattern(
|
|
396
|
+
self,
|
|
397
|
+
content: str,
|
|
398
|
+
pattern_type: str,
|
|
399
|
+
classification: Classification | str | None = None,
|
|
400
|
+
auto_classify: bool = True,
|
|
401
|
+
metadata: dict[str, Any] | None = None,
|
|
402
|
+
) -> dict[str, Any] | None:
|
|
403
|
+
"""Store a pattern in long-term memory with security controls.
|
|
404
|
+
|
|
405
|
+
Args:
|
|
406
|
+
content: Pattern content
|
|
407
|
+
pattern_type: Type of pattern (algorithm, protocol, etc.)
|
|
408
|
+
classification: Security classification (PUBLIC/INTERNAL/SENSITIVE)
|
|
409
|
+
auto_classify: Auto-detect classification from content
|
|
410
|
+
metadata: Additional metadata to store
|
|
411
|
+
|
|
412
|
+
Returns:
|
|
413
|
+
Storage result with pattern_id and classification, or None if failed
|
|
414
|
+
|
|
415
|
+
"""
|
|
416
|
+
if not self._long_term:
|
|
417
|
+
logger.error("long_term_memory_unavailable")
|
|
418
|
+
return None
|
|
419
|
+
|
|
420
|
+
try:
|
|
421
|
+
# Convert string classification to enum if needed
|
|
422
|
+
explicit_class = None
|
|
423
|
+
if classification is not None:
|
|
424
|
+
if isinstance(classification, str):
|
|
425
|
+
explicit_class = Classification[classification.upper()]
|
|
426
|
+
else:
|
|
427
|
+
explicit_class = classification
|
|
428
|
+
|
|
429
|
+
result = self._long_term.store_pattern(
|
|
430
|
+
content=content,
|
|
431
|
+
pattern_type=pattern_type,
|
|
432
|
+
user_id=self.user_id,
|
|
433
|
+
explicit_classification=explicit_class,
|
|
434
|
+
auto_classify=auto_classify,
|
|
435
|
+
custom_metadata=metadata,
|
|
436
|
+
)
|
|
437
|
+
logger.info(
|
|
438
|
+
"pattern_persisted",
|
|
439
|
+
pattern_id=result.get("pattern_id"),
|
|
440
|
+
classification=result.get("classification"),
|
|
441
|
+
)
|
|
442
|
+
return result
|
|
443
|
+
except Exception as e:
|
|
444
|
+
logger.error("persist_pattern_failed", error=str(e))
|
|
445
|
+
return None
|
|
446
|
+
|
|
447
|
+
def recall_pattern(
|
|
448
|
+
self,
|
|
449
|
+
pattern_id: str,
|
|
450
|
+
check_permissions: bool = True,
|
|
451
|
+
) -> dict[str, Any] | None:
|
|
452
|
+
"""Retrieve a pattern from long-term memory.
|
|
453
|
+
|
|
454
|
+
Args:
|
|
455
|
+
pattern_id: ID of pattern to retrieve
|
|
456
|
+
check_permissions: Verify user has access to pattern
|
|
457
|
+
|
|
458
|
+
Returns:
|
|
459
|
+
Pattern data with content and metadata, or None if not found
|
|
460
|
+
|
|
461
|
+
"""
|
|
462
|
+
if not self._long_term:
|
|
463
|
+
logger.error("long_term_memory_unavailable")
|
|
464
|
+
return None
|
|
465
|
+
|
|
466
|
+
try:
|
|
467
|
+
return self._long_term.retrieve_pattern(
|
|
468
|
+
pattern_id=pattern_id,
|
|
469
|
+
user_id=self.user_id,
|
|
470
|
+
check_permissions=check_permissions,
|
|
471
|
+
)
|
|
472
|
+
except Exception as e:
|
|
473
|
+
logger.error("recall_pattern_failed", pattern_id=pattern_id, error=str(e))
|
|
474
|
+
return None
|
|
475
|
+
|
|
476
|
+
def search_patterns(
|
|
477
|
+
self,
|
|
478
|
+
query: str | None = None,
|
|
479
|
+
pattern_type: str | None = None,
|
|
480
|
+
classification: Classification | None = None,
|
|
481
|
+
limit: int = 10,
|
|
482
|
+
) -> list[dict[str, Any]]:
|
|
483
|
+
"""Search patterns in long-term memory.
|
|
484
|
+
|
|
485
|
+
Args:
|
|
486
|
+
query: Text to search for in pattern content
|
|
487
|
+
pattern_type: Filter by pattern type
|
|
488
|
+
classification: Filter by classification level
|
|
489
|
+
limit: Maximum results to return
|
|
490
|
+
|
|
491
|
+
Returns:
|
|
492
|
+
List of matching patterns
|
|
493
|
+
|
|
494
|
+
"""
|
|
495
|
+
if not self._long_term:
|
|
496
|
+
return []
|
|
497
|
+
|
|
498
|
+
# Note: Full search implementation depends on storage backend
|
|
499
|
+
# For now, return patterns matching type/classification
|
|
500
|
+
patterns: list[dict[str, Any]] = []
|
|
501
|
+
# This would be implemented based on the storage backend
|
|
502
|
+
return patterns
|
|
503
|
+
|
|
504
|
+
# =========================================================================
|
|
505
|
+
# PATTERN PROMOTION (SHORT-TERM → LONG-TERM)
|
|
506
|
+
# =========================================================================
|
|
507
|
+
|
|
508
|
+
def promote_pattern(
|
|
509
|
+
self,
|
|
510
|
+
staged_pattern_id: str,
|
|
511
|
+
classification: Classification | str | None = None,
|
|
512
|
+
auto_classify: bool = True,
|
|
513
|
+
) -> dict[str, Any] | None:
|
|
514
|
+
"""Promote a staged pattern from short-term to long-term memory.
|
|
515
|
+
|
|
516
|
+
Args:
|
|
517
|
+
staged_pattern_id: ID of staged pattern to promote
|
|
518
|
+
classification: Override classification (or auto-detect)
|
|
519
|
+
auto_classify: Auto-detect classification from content
|
|
520
|
+
|
|
521
|
+
Returns:
|
|
522
|
+
Long-term storage result, or None if failed
|
|
523
|
+
|
|
524
|
+
"""
|
|
525
|
+
if not self._short_term or not self._long_term:
|
|
526
|
+
logger.error("memory_backends_unavailable")
|
|
527
|
+
return None
|
|
528
|
+
|
|
529
|
+
# Retrieve staged pattern
|
|
530
|
+
staged_patterns = self.get_staged_patterns()
|
|
531
|
+
staged = next(
|
|
532
|
+
(p for p in staged_patterns if p.get("pattern_id") == staged_pattern_id),
|
|
533
|
+
None,
|
|
534
|
+
)
|
|
535
|
+
|
|
536
|
+
if not staged:
|
|
537
|
+
logger.warning("staged_pattern_not_found", pattern_id=staged_pattern_id)
|
|
538
|
+
return None
|
|
539
|
+
|
|
540
|
+
# Persist to long-term storage
|
|
541
|
+
# Content is stored in context dict by stage_pattern
|
|
542
|
+
context = staged.get("context", {})
|
|
543
|
+
content = context.get("content", "") or staged.get("description", "")
|
|
544
|
+
result = self.persist_pattern(
|
|
545
|
+
content=content,
|
|
546
|
+
pattern_type=staged.get("pattern_type", "general"),
|
|
547
|
+
classification=classification,
|
|
548
|
+
auto_classify=auto_classify,
|
|
549
|
+
metadata=context,
|
|
550
|
+
)
|
|
551
|
+
|
|
552
|
+
if result:
|
|
553
|
+
# Remove from staging (use promote_pattern which handles deletion)
|
|
554
|
+
try:
|
|
555
|
+
self._short_term.promote_pattern(staged_pattern_id, self.credentials)
|
|
556
|
+
except PermissionError:
|
|
557
|
+
# If we can't promote (delete from staging), just log it
|
|
558
|
+
logger.warning("could_not_remove_from_staging", pattern_id=staged_pattern_id)
|
|
559
|
+
logger.info(
|
|
560
|
+
"pattern_promoted",
|
|
561
|
+
staged_id=staged_pattern_id,
|
|
562
|
+
long_term_id=result.get("pattern_id"),
|
|
563
|
+
)
|
|
564
|
+
|
|
565
|
+
return result
|
|
566
|
+
|
|
567
|
+
# =========================================================================
|
|
568
|
+
# UTILITY METHODS
|
|
569
|
+
# =========================================================================
|
|
570
|
+
|
|
571
|
+
@property
|
|
572
|
+
def has_short_term(self) -> bool:
|
|
573
|
+
"""Check if short-term memory is available."""
|
|
574
|
+
return self._short_term is not None
|
|
575
|
+
|
|
576
|
+
@property
|
|
577
|
+
def has_long_term(self) -> bool:
|
|
578
|
+
"""Check if long-term memory is available."""
|
|
579
|
+
return self._long_term is not None
|
|
580
|
+
|
|
581
|
+
@property
|
|
582
|
+
def redis_status(self) -> RedisStatus | None:
|
|
583
|
+
"""Get Redis connection status."""
|
|
584
|
+
return self._redis_status
|
|
585
|
+
|
|
586
|
+
@property
|
|
587
|
+
def using_real_redis(self) -> bool:
|
|
588
|
+
"""Check if using real Redis (not mock)."""
|
|
589
|
+
return (
|
|
590
|
+
self._redis_status is not None
|
|
591
|
+
and self._redis_status.available
|
|
592
|
+
and self._redis_status.method != RedisStartMethod.MOCK
|
|
593
|
+
)
|
|
594
|
+
|
|
595
|
+
def health_check(self) -> dict[str, Any]:
|
|
596
|
+
"""Check health of memory backends.
|
|
597
|
+
|
|
598
|
+
Returns:
|
|
599
|
+
Status of each memory backend
|
|
600
|
+
|
|
601
|
+
"""
|
|
602
|
+
redis_info: dict[str, Any] = {
|
|
603
|
+
"available": self.has_short_term,
|
|
604
|
+
"mock_mode": not self.using_real_redis,
|
|
605
|
+
}
|
|
606
|
+
if self._redis_status:
|
|
607
|
+
redis_info["method"] = self._redis_status.method.value
|
|
608
|
+
redis_info["host"] = self._redis_status.host
|
|
609
|
+
redis_info["port"] = self._redis_status.port
|
|
610
|
+
|
|
611
|
+
return {
|
|
612
|
+
"short_term": redis_info,
|
|
613
|
+
"long_term": {
|
|
614
|
+
"available": self.has_long_term,
|
|
615
|
+
"storage_dir": self.config.storage_dir,
|
|
616
|
+
"encryption": self.config.encryption_enabled,
|
|
617
|
+
},
|
|
618
|
+
"environment": self.config.environment.value,
|
|
619
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""Prompt performance metrics tracking and analysis.
|
|
2
|
+
|
|
3
|
+
This module provides tools for tracking, analyzing, and optimizing
|
|
4
|
+
prompt performance across the Empathy Framework.
|
|
5
|
+
|
|
6
|
+
Copyright 2026 Smart-AI-Memory
|
|
7
|
+
Licensed under Fair Source License 0.9
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from empathy_os.metrics.prompt_metrics import MetricsTracker, PromptMetrics
|
|
11
|
+
|
|
12
|
+
__all__ = ["MetricsTracker", "PromptMetrics"]
|