empathy-framework 5.1.1__py3-none-any.whl → 5.2.1__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 (71) hide show
  1. {empathy_framework-5.1.1.dist-info → empathy_framework-5.2.1.dist-info}/METADATA +52 -3
  2. {empathy_framework-5.1.1.dist-info → empathy_framework-5.2.1.dist-info}/RECORD +69 -28
  3. empathy_os/cli_router.py +9 -0
  4. empathy_os/core_modules/__init__.py +15 -0
  5. empathy_os/mcp/__init__.py +10 -0
  6. empathy_os/mcp/server.py +506 -0
  7. empathy_os/memory/control_panel.py +1 -131
  8. empathy_os/memory/control_panel_support.py +145 -0
  9. empathy_os/memory/encryption.py +159 -0
  10. empathy_os/memory/long_term.py +41 -626
  11. empathy_os/memory/long_term_types.py +99 -0
  12. empathy_os/memory/mixins/__init__.py +25 -0
  13. empathy_os/memory/mixins/backend_init_mixin.py +244 -0
  14. empathy_os/memory/mixins/capabilities_mixin.py +199 -0
  15. empathy_os/memory/mixins/handoff_mixin.py +208 -0
  16. empathy_os/memory/mixins/lifecycle_mixin.py +49 -0
  17. empathy_os/memory/mixins/long_term_mixin.py +352 -0
  18. empathy_os/memory/mixins/promotion_mixin.py +109 -0
  19. empathy_os/memory/mixins/short_term_mixin.py +182 -0
  20. empathy_os/memory/short_term.py +7 -0
  21. empathy_os/memory/simple_storage.py +302 -0
  22. empathy_os/memory/storage_backend.py +167 -0
  23. empathy_os/memory/unified.py +21 -1120
  24. empathy_os/meta_workflows/cli_commands/__init__.py +56 -0
  25. empathy_os/meta_workflows/cli_commands/agent_commands.py +321 -0
  26. empathy_os/meta_workflows/cli_commands/analytics_commands.py +442 -0
  27. empathy_os/meta_workflows/cli_commands/config_commands.py +232 -0
  28. empathy_os/meta_workflows/cli_commands/memory_commands.py +182 -0
  29. empathy_os/meta_workflows/cli_commands/template_commands.py +354 -0
  30. empathy_os/meta_workflows/cli_commands/workflow_commands.py +382 -0
  31. empathy_os/meta_workflows/cli_meta_workflows.py +52 -1802
  32. empathy_os/models/telemetry/__init__.py +71 -0
  33. empathy_os/models/telemetry/analytics.py +594 -0
  34. empathy_os/models/telemetry/backend.py +196 -0
  35. empathy_os/models/telemetry/data_models.py +431 -0
  36. empathy_os/models/telemetry/storage.py +489 -0
  37. empathy_os/orchestration/__init__.py +35 -0
  38. empathy_os/orchestration/execution_strategies.py +481 -0
  39. empathy_os/orchestration/meta_orchestrator.py +488 -1
  40. empathy_os/routing/workflow_registry.py +36 -0
  41. empathy_os/telemetry/cli.py +19 -724
  42. empathy_os/telemetry/commands/__init__.py +14 -0
  43. empathy_os/telemetry/commands/dashboard_commands.py +696 -0
  44. empathy_os/tools.py +183 -0
  45. empathy_os/workflows/__init__.py +5 -0
  46. empathy_os/workflows/autonomous_test_gen.py +860 -161
  47. empathy_os/workflows/base.py +6 -2
  48. empathy_os/workflows/code_review.py +4 -1
  49. empathy_os/workflows/document_gen/__init__.py +25 -0
  50. empathy_os/workflows/document_gen/config.py +30 -0
  51. empathy_os/workflows/document_gen/report_formatter.py +162 -0
  52. empathy_os/workflows/document_gen/workflow.py +1426 -0
  53. empathy_os/workflows/document_gen.py +22 -1598
  54. empathy_os/workflows/security_audit.py +2 -2
  55. empathy_os/workflows/security_audit_phase3.py +7 -4
  56. empathy_os/workflows/seo_optimization.py +633 -0
  57. empathy_os/workflows/test_gen/__init__.py +52 -0
  58. empathy_os/workflows/test_gen/ast_analyzer.py +249 -0
  59. empathy_os/workflows/test_gen/config.py +88 -0
  60. empathy_os/workflows/test_gen/data_models.py +38 -0
  61. empathy_os/workflows/test_gen/report_formatter.py +289 -0
  62. empathy_os/workflows/test_gen/test_templates.py +381 -0
  63. empathy_os/workflows/test_gen/workflow.py +655 -0
  64. empathy_os/workflows/test_gen.py +42 -1905
  65. empathy_os/memory/types 2.py +0 -441
  66. empathy_os/models/telemetry.py +0 -1660
  67. {empathy_framework-5.1.1.dist-info → empathy_framework-5.2.1.dist-info}/WHEEL +0 -0
  68. {empathy_framework-5.1.1.dist-info → empathy_framework-5.2.1.dist-info}/entry_points.txt +0 -0
  69. {empathy_framework-5.1.1.dist-info → empathy_framework-5.2.1.dist-info}/licenses/LICENSE +0 -0
  70. {empathy_framework-5.1.1.dist-info → empathy_framework-5.2.1.dist-info}/licenses/LICENSE_CHANGE_ANNOUNCEMENT.md +0 -0
  71. {empathy_framework-5.1.1.dist-info → empathy_framework-5.2.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,99 @@
1
+ """Type definitions for long-term memory system
2
+
3
+ This module contains data classes, enums, and exceptions used by the long-term
4
+ memory system. Extracted from long_term.py for better modularity and testability.
5
+
6
+ Key Types:
7
+ - Classification: Three-tier security classification system
8
+ - ClassificationRules: Security rules per classification level
9
+ - PatternMetadata: Metadata for stored patterns
10
+ - SecurePattern: Pattern with content and metadata
11
+ - SecurityError, PermissionError: Exception types
12
+
13
+ Copyright 2025 Smart AI Memory, LLC
14
+ Licensed under Fair Source 0.9
15
+ """
16
+
17
+ from dataclasses import dataclass, field
18
+ from enum import Enum
19
+ from typing import Any
20
+
21
+
22
+ class Classification(Enum):
23
+ """Three-tier classification system for MemDocs patterns"""
24
+
25
+ PUBLIC = "PUBLIC" # Shareable across organization, anonymized
26
+ INTERNAL = "INTERNAL" # Team/project only, no PII or secrets
27
+ SENSITIVE = "SENSITIVE" # Encrypted at rest, access-controlled (HIPAA, finance)
28
+
29
+
30
+ @dataclass
31
+ class ClassificationRules:
32
+ """Security rules for each classification level"""
33
+
34
+ classification: Classification
35
+ encryption_required: bool
36
+ retention_days: int
37
+ access_level: str # "all_users", "project_team", "explicit_permission"
38
+ audit_all_access: bool = False
39
+
40
+
41
+ # Default classification rules based on enterprise security policy
42
+ DEFAULT_CLASSIFICATION_RULES: dict[Classification, ClassificationRules] = {
43
+ Classification.PUBLIC: ClassificationRules(
44
+ classification=Classification.PUBLIC,
45
+ encryption_required=False,
46
+ retention_days=365,
47
+ access_level="all_users",
48
+ audit_all_access=False,
49
+ ),
50
+ Classification.INTERNAL: ClassificationRules(
51
+ classification=Classification.INTERNAL,
52
+ encryption_required=False,
53
+ retention_days=180,
54
+ access_level="project_team",
55
+ audit_all_access=False,
56
+ ),
57
+ Classification.SENSITIVE: ClassificationRules(
58
+ classification=Classification.SENSITIVE,
59
+ encryption_required=True,
60
+ retention_days=90,
61
+ access_level="explicit_permission",
62
+ audit_all_access=True,
63
+ ),
64
+ }
65
+
66
+
67
+ @dataclass
68
+ class PatternMetadata:
69
+ """Metadata for stored MemDocs patterns"""
70
+
71
+ pattern_id: str
72
+ created_by: str
73
+ created_at: str
74
+ classification: str
75
+ retention_days: int
76
+ encrypted: bool
77
+ pattern_type: str
78
+ sanitization_applied: bool
79
+ pii_removed: int
80
+ secrets_detected: int
81
+ access_control: dict[str, Any] = field(default_factory=dict)
82
+ custom_metadata: dict[str, Any] = field(default_factory=dict)
83
+
84
+
85
+ @dataclass
86
+ class SecurePattern:
87
+ """Represents a securely stored pattern"""
88
+
89
+ pattern_id: str
90
+ content: str
91
+ metadata: PatternMetadata
92
+
93
+
94
+ class SecurityError(Exception):
95
+ """Raised when security policy is violated"""
96
+
97
+
98
+ class PermissionError(Exception):
99
+ """Raised when access is denied"""
@@ -0,0 +1,25 @@
1
+ """Memory mixins for UnifiedMemory composition.
2
+
3
+ Provides modular capabilities through mixin composition pattern.
4
+
5
+ Copyright 2025 Smart AI Memory, LLC
6
+ Licensed under Fair Source 0.9
7
+ """
8
+
9
+ from .backend_init_mixin import BackendInitMixin
10
+ from .capabilities_mixin import CapabilitiesMixin
11
+ from .handoff_mixin import HandoffAndExportMixin
12
+ from .lifecycle_mixin import LifecycleMixin
13
+ from .long_term_mixin import LongTermOperationsMixin
14
+ from .promotion_mixin import PatternPromotionMixin
15
+ from .short_term_mixin import ShortTermOperationsMixin
16
+
17
+ __all__ = [
18
+ "BackendInitMixin",
19
+ "CapabilitiesMixin",
20
+ "HandoffAndExportMixin",
21
+ "LifecycleMixin",
22
+ "LongTermOperationsMixin",
23
+ "PatternPromotionMixin",
24
+ "ShortTermOperationsMixin",
25
+ ]
@@ -0,0 +1,244 @@
1
+ """Backend initialization mixin for UnifiedMemory.
2
+
3
+ Handles initialization of file session, Redis, and long-term memory backends.
4
+
5
+ Copyright 2025 Smart AI Memory, LLC
6
+ Licensed under Fair Source 0.9
7
+ """
8
+
9
+ from typing import TYPE_CHECKING, Any
10
+
11
+ import structlog
12
+
13
+ if TYPE_CHECKING:
14
+ from ..file_session import FileSessionMemory
15
+ from ..long_term import LongTermMemory, SecureMemDocsIntegration
16
+ from ..redis_bootstrap import RedisStatus
17
+ from ..short_term import RedisShortTermMemory
18
+
19
+ logger = structlog.get_logger(__name__)
20
+
21
+
22
+ class BackendInitMixin:
23
+ """Mixin providing backend initialization for UnifiedMemory."""
24
+
25
+ # Type hints for attributes that will be provided by UnifiedMemory
26
+ user_id: str
27
+ config: Any # MemoryConfig
28
+ _file_session: "FileSessionMemory | None"
29
+ _short_term: "RedisShortTermMemory | None"
30
+ _long_term: "SecureMemDocsIntegration | None"
31
+ _simple_long_term: "LongTermMemory | None"
32
+ _redis_status: "RedisStatus | None"
33
+ _initialized: bool
34
+
35
+ # =========================================================================
36
+ # BACKEND INITIALIZATION
37
+ # =========================================================================
38
+
39
+ def _initialize_backends(self):
40
+ """Initialize short-term and long-term memory backends.
41
+
42
+ File-First Architecture:
43
+ 1. FileSessionMemory is always initialized (primary storage)
44
+ 2. Redis is optional (for real-time features like pub/sub)
45
+ 3. Falls back gracefully when Redis is unavailable
46
+ """
47
+ from ..claude_memory import ClaudeMemoryConfig
48
+ from ..config import get_redis_memory
49
+ from ..file_session import FileSessionConfig, FileSessionMemory
50
+ from ..long_term import LongTermMemory, SecureMemDocsIntegration
51
+ from ..redis_bootstrap import RedisStartMethod, RedisStatus, ensure_redis
52
+ from ..short_term import RedisShortTermMemory
53
+
54
+ if self._initialized:
55
+ return
56
+
57
+ # Initialize file-based session memory (PRIMARY - always available)
58
+ if self.config.file_session_enabled:
59
+ try:
60
+ file_config = FileSessionConfig(base_dir=self.config.file_session_dir)
61
+ self._file_session = FileSessionMemory(
62
+ user_id=self.user_id,
63
+ config=file_config,
64
+ )
65
+ logger.info(
66
+ "file_session_memory_initialized",
67
+ base_dir=self.config.file_session_dir,
68
+ session_id=self._file_session._state.session_id,
69
+ )
70
+ except Exception as e:
71
+ logger.error("file_session_memory_failed", error=str(e))
72
+ self._file_session = None
73
+
74
+ # Initialize Redis short-term memory (OPTIONAL - for real-time features)
75
+ try:
76
+ if self.config.redis_mock:
77
+ self._short_term = RedisShortTermMemory(use_mock=True)
78
+ self._redis_status = RedisStatus(
79
+ available=False,
80
+ method=RedisStartMethod.MOCK,
81
+ message="Mock mode explicitly enabled",
82
+ )
83
+ elif self.config.redis_url:
84
+ self._short_term = get_redis_memory(url=self.config.redis_url)
85
+ self._redis_status = RedisStatus(
86
+ available=True,
87
+ method=RedisStartMethod.ALREADY_RUNNING,
88
+ message="Connected via REDIS_URL",
89
+ )
90
+ # Use auto-start if enabled
91
+ elif self.config.redis_auto_start:
92
+ self._redis_status = ensure_redis(
93
+ host=self.config.redis_host,
94
+ port=self.config.redis_port,
95
+ auto_start=True,
96
+ verbose=True,
97
+ )
98
+ if self._redis_status.available:
99
+ self._short_term = RedisShortTermMemory(
100
+ host=self.config.redis_host,
101
+ port=self.config.redis_port,
102
+ use_mock=False,
103
+ )
104
+ else:
105
+ # File session is primary, so Redis mock is not needed
106
+ self._short_term = None
107
+ self._redis_status = RedisStatus(
108
+ available=False,
109
+ method=RedisStartMethod.MOCK,
110
+ message="Redis unavailable, using file-based storage",
111
+ )
112
+ else:
113
+ # Try to connect to existing Redis
114
+ try:
115
+ self._short_term = get_redis_memory()
116
+ if self._short_term.is_connected():
117
+ self._redis_status = RedisStatus(
118
+ available=True,
119
+ method=RedisStartMethod.ALREADY_RUNNING,
120
+ message="Connected to existing Redis",
121
+ )
122
+ else:
123
+ self._short_term = None
124
+ self._redis_status = RedisStatus(
125
+ available=False,
126
+ method=RedisStartMethod.MOCK,
127
+ message="Redis not available, using file-based storage",
128
+ )
129
+ except Exception:
130
+ self._short_term = None
131
+ self._redis_status = RedisStatus(
132
+ available=False,
133
+ method=RedisStartMethod.MOCK,
134
+ message="Redis not available, using file-based storage",
135
+ )
136
+
137
+ logger.info(
138
+ "short_term_memory_initialized",
139
+ redis_available=self._redis_status.available if self._redis_status else False,
140
+ file_session_available=self._file_session is not None,
141
+ redis_method=self._redis_status.method.value if self._redis_status else "none",
142
+ environment=self.config.environment.value,
143
+ )
144
+
145
+ # Fail if Redis is required but not available
146
+ if self.config.redis_required and not (
147
+ self._redis_status and self._redis_status.available
148
+ ):
149
+ raise RuntimeError("Redis is required but not available")
150
+
151
+ except RuntimeError:
152
+ raise # Re-raise required Redis error
153
+ except Exception as e:
154
+ logger.warning("redis_initialization_failed", error=str(e))
155
+ self._short_term = None
156
+ self._redis_status = RedisStatus(
157
+ available=False,
158
+ method=RedisStartMethod.MOCK,
159
+ message=f"Failed to initialize: {e}",
160
+ )
161
+
162
+ # Initialize long-term memory (SecureMemDocs)
163
+ try:
164
+ claude_config = ClaudeMemoryConfig(
165
+ enabled=self.config.claude_memory_enabled,
166
+ load_enterprise=self.config.load_enterprise_memory,
167
+ load_project=self.config.load_project_memory,
168
+ load_user=self.config.load_user_memory,
169
+ )
170
+ self._long_term = SecureMemDocsIntegration(
171
+ claude_memory_config=claude_config,
172
+ storage_dir=self.config.storage_dir,
173
+ enable_encryption=self.config.encryption_enabled,
174
+ )
175
+
176
+ logger.info(
177
+ "long_term_memory_initialized",
178
+ storage_dir=self.config.storage_dir,
179
+ encryption=self.config.encryption_enabled,
180
+ )
181
+ except Exception as e:
182
+ logger.error("long_term_memory_failed", error=str(e))
183
+ self._long_term = None
184
+
185
+ # Initialize simple long-term memory (for testing and simple use cases)
186
+ try:
187
+ self._simple_long_term = LongTermMemory(storage_path=self.config.storage_dir)
188
+ logger.debug("simple_long_term_memory_initialized")
189
+ except Exception as e:
190
+ logger.error("simple_long_term_memory_failed", error=str(e))
191
+ self._simple_long_term = None
192
+
193
+ self._initialized = True
194
+
195
+ def get_backend_status(self) -> dict[str, Any]:
196
+ """Get the current status of all memory backends.
197
+
198
+ Returns a structured dict suitable for health checks, debugging,
199
+ and dashboard display. Can be serialized to JSON.
200
+
201
+ Returns:
202
+ dict with keys:
203
+ - environment: Current environment (development/staging/production)
204
+ - short_term: Status of Redis-based short-term memory
205
+ - long_term: Status of persistent long-term memory
206
+ - initialized: Whether backends have been initialized
207
+
208
+ Example:
209
+ >>> memory = UnifiedMemory(user_id="agent")
210
+ >>> status = memory.get_backend_status()
211
+ >>> print(status["short_term"]["available"])
212
+ True
213
+
214
+ """
215
+ from ..redis_bootstrap import RedisStartMethod
216
+
217
+ short_term_status: dict[str, Any] = {
218
+ "available": False,
219
+ "mock": True,
220
+ "method": "unknown",
221
+ "message": "Not initialized",
222
+ }
223
+
224
+ if self._redis_status:
225
+ short_term_status = {
226
+ "available": self._redis_status.available,
227
+ "mock": not self._redis_status.available
228
+ or self._redis_status.method == RedisStartMethod.MOCK,
229
+ "method": self._redis_status.method.value,
230
+ "message": self._redis_status.message,
231
+ }
232
+
233
+ long_term_status: dict[str, Any] = {
234
+ "available": self._long_term is not None,
235
+ "storage_dir": self.config.storage_dir,
236
+ "encryption_enabled": self.config.encryption_enabled,
237
+ }
238
+
239
+ return {
240
+ "environment": self.config.environment.value,
241
+ "initialized": self._initialized,
242
+ "short_term": short_term_status,
243
+ "long_term": long_term_status,
244
+ }
@@ -0,0 +1,199 @@
1
+ """Capabilities and health check mixin for UnifiedMemory.
2
+
3
+ Provides backend availability checks, health monitoring, and feature detection.
4
+
5
+ Copyright 2025 Smart AI Memory, LLC
6
+ Licensed under Fair Source 0.9
7
+ """
8
+
9
+ from typing import TYPE_CHECKING, Any
10
+
11
+ if TYPE_CHECKING:
12
+ from ..file_session import FileSessionMemory
13
+ from ..long_term import LongTermMemory
14
+ from ..redis_bootstrap import RedisStatus
15
+ from ..short_term import RedisShortTermMemory
16
+
17
+
18
+ class CapabilitiesMixin:
19
+ """Mixin providing capability detection and health checks for UnifiedMemory."""
20
+
21
+ # Type hints for attributes that will be provided by UnifiedMemory
22
+ _file_session: "FileSessionMemory | None"
23
+ _short_term: "RedisShortTermMemory | None"
24
+ _long_term: Any # SecureMemDocsIntegration
25
+ _simple_long_term: "LongTermMemory | None"
26
+ _redis_status: "RedisStatus | None"
27
+ config: Any # MemoryConfig
28
+
29
+ # =========================================================================
30
+ # BACKEND AVAILABILITY CHECKS
31
+ # =========================================================================
32
+
33
+ @property
34
+ def has_short_term(self) -> bool:
35
+ """Check if short-term memory is available."""
36
+ return self._short_term is not None
37
+
38
+ @property
39
+ def has_long_term(self) -> bool:
40
+ """Check if long-term memory is available."""
41
+ return self._long_term is not None
42
+
43
+ @property
44
+ def redis_status(self) -> "RedisStatus | None":
45
+ """Get Redis connection status."""
46
+ return self._redis_status
47
+
48
+ @property
49
+ def using_real_redis(self) -> bool:
50
+ """Check if using real Redis (not mock)."""
51
+ from ..redis_bootstrap import RedisStartMethod
52
+
53
+ return (
54
+ self._redis_status is not None
55
+ and self._redis_status.available
56
+ and self._redis_status.method != RedisStartMethod.MOCK
57
+ )
58
+
59
+ @property
60
+ def short_term(self) -> "RedisShortTermMemory":
61
+ """Get short-term memory backend for direct access (testing).
62
+
63
+ Returns:
64
+ RedisShortTermMemory instance
65
+
66
+ Raises:
67
+ RuntimeError: If short-term memory is not initialized
68
+
69
+ """
70
+ if self._short_term is None:
71
+ raise RuntimeError("Short-term memory not initialized")
72
+ return self._short_term
73
+
74
+ @property
75
+ def long_term(self) -> "LongTermMemory":
76
+ """Get simple long-term memory backend for direct access (testing).
77
+
78
+ Returns:
79
+ LongTermMemory instance
80
+
81
+ Raises:
82
+ RuntimeError: If long-term memory is not initialized
83
+
84
+ Note:
85
+ For production use with security features (PII scrubbing, encryption),
86
+ use persist_pattern() and recall_pattern() methods instead.
87
+
88
+ """
89
+ if self._simple_long_term is None:
90
+ raise RuntimeError("Long-term memory not initialized")
91
+ return self._simple_long_term
92
+
93
+ # =========================================================================
94
+ # HEALTH CHECKS
95
+ # =========================================================================
96
+
97
+ def health_check(self) -> dict[str, Any]:
98
+ """Check health of memory backends.
99
+
100
+ Returns:
101
+ Status of each memory backend
102
+
103
+ """
104
+ redis_info: dict[str, Any] = {
105
+ "available": self.has_short_term,
106
+ "mock_mode": not self.using_real_redis,
107
+ }
108
+ if self._redis_status:
109
+ redis_info["method"] = self._redis_status.method.value
110
+ redis_info["host"] = self._redis_status.host
111
+ redis_info["port"] = self._redis_status.port
112
+
113
+ return {
114
+ "file_session": {
115
+ "available": self._file_session is not None,
116
+ "session_id": self._file_session._state.session_id if self._file_session else None,
117
+ "base_dir": self.config.file_session_dir,
118
+ },
119
+ "short_term": redis_info,
120
+ "long_term": {
121
+ "available": self.has_long_term,
122
+ "storage_dir": self.config.storage_dir,
123
+ "encryption": self.config.encryption_enabled,
124
+ },
125
+ "environment": self.config.environment.value,
126
+ }
127
+
128
+ # =========================================================================
129
+ # CAPABILITY DETECTION (File-First Architecture)
130
+ # =========================================================================
131
+
132
+ @property
133
+ def has_file_session(self) -> bool:
134
+ """Check if file-based session memory is available (always True if enabled)."""
135
+ return self._file_session is not None
136
+
137
+ @property
138
+ def file_session(self) -> "FileSessionMemory":
139
+ """Get file session memory backend for direct access.
140
+
141
+ Returns:
142
+ FileSessionMemory instance
143
+
144
+ Raises:
145
+ RuntimeError: If file session memory is not initialized
146
+ """
147
+ if self._file_session is None:
148
+ raise RuntimeError("File session memory not initialized")
149
+ return self._file_session
150
+
151
+ def supports_realtime(self) -> bool:
152
+ """Check if real-time features are available (requires Redis).
153
+
154
+ Real-time features include:
155
+ - Pub/Sub messaging between agents
156
+ - Cross-session coordination
157
+ - Distributed task queues
158
+
159
+ Returns:
160
+ True if Redis is available and connected
161
+ """
162
+ return self.using_real_redis
163
+
164
+ def supports_distributed(self) -> bool:
165
+ """Check if distributed features are available (requires Redis).
166
+
167
+ Distributed features include:
168
+ - Multi-process coordination
169
+ - Cross-session state sharing
170
+ - Agent discovery
171
+
172
+ Returns:
173
+ True if Redis is available and connected
174
+ """
175
+ return self.using_real_redis
176
+
177
+ def supports_persistence(self) -> bool:
178
+ """Check if persistence is available (always True with file-first).
179
+
180
+ Returns:
181
+ True if file session or long-term memory is available
182
+ """
183
+ return self._file_session is not None or self._long_term is not None
184
+
185
+ def get_capabilities(self) -> dict[str, bool]:
186
+ """Get a summary of available memory capabilities.
187
+
188
+ Returns:
189
+ Dictionary mapping capability names to availability
190
+ """
191
+ return {
192
+ "file_session": self.has_file_session,
193
+ "redis": self.using_real_redis,
194
+ "long_term": self.has_long_term,
195
+ "persistence": self.supports_persistence(),
196
+ "realtime": self.supports_realtime(),
197
+ "distributed": self.supports_distributed(),
198
+ "encryption": self.config.encryption_enabled and self.has_long_term,
199
+ }