alma-memory 0.5.1__py3-none-any.whl → 0.7.0__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 (111) hide show
  1. alma/__init__.py +296 -226
  2. alma/compression/__init__.py +33 -0
  3. alma/compression/pipeline.py +980 -0
  4. alma/confidence/__init__.py +47 -47
  5. alma/confidence/engine.py +540 -540
  6. alma/confidence/types.py +351 -351
  7. alma/config/loader.py +157 -157
  8. alma/consolidation/__init__.py +23 -23
  9. alma/consolidation/engine.py +678 -678
  10. alma/consolidation/prompts.py +84 -84
  11. alma/core.py +1189 -430
  12. alma/domains/__init__.py +30 -30
  13. alma/domains/factory.py +359 -359
  14. alma/domains/schemas.py +448 -448
  15. alma/domains/types.py +272 -272
  16. alma/events/__init__.py +75 -75
  17. alma/events/emitter.py +285 -284
  18. alma/events/storage_mixin.py +246 -246
  19. alma/events/types.py +126 -126
  20. alma/events/webhook.py +425 -425
  21. alma/exceptions.py +49 -49
  22. alma/extraction/__init__.py +31 -31
  23. alma/extraction/auto_learner.py +265 -265
  24. alma/extraction/extractor.py +420 -420
  25. alma/graph/__init__.py +106 -106
  26. alma/graph/backends/__init__.py +32 -32
  27. alma/graph/backends/kuzu.py +624 -624
  28. alma/graph/backends/memgraph.py +432 -432
  29. alma/graph/backends/memory.py +236 -236
  30. alma/graph/backends/neo4j.py +417 -417
  31. alma/graph/base.py +159 -159
  32. alma/graph/extraction.py +198 -198
  33. alma/graph/store.py +860 -860
  34. alma/harness/__init__.py +35 -35
  35. alma/harness/base.py +386 -386
  36. alma/harness/domains.py +705 -705
  37. alma/initializer/__init__.py +37 -37
  38. alma/initializer/initializer.py +418 -418
  39. alma/initializer/types.py +250 -250
  40. alma/integration/__init__.py +62 -62
  41. alma/integration/claude_agents.py +444 -444
  42. alma/integration/helena.py +423 -423
  43. alma/integration/victor.py +471 -471
  44. alma/learning/__init__.py +101 -86
  45. alma/learning/decay.py +878 -0
  46. alma/learning/forgetting.py +1446 -1446
  47. alma/learning/heuristic_extractor.py +390 -390
  48. alma/learning/protocols.py +374 -374
  49. alma/learning/validation.py +346 -346
  50. alma/mcp/__init__.py +123 -45
  51. alma/mcp/__main__.py +156 -156
  52. alma/mcp/resources.py +122 -122
  53. alma/mcp/server.py +955 -591
  54. alma/mcp/tools.py +3254 -509
  55. alma/observability/__init__.py +91 -84
  56. alma/observability/config.py +302 -302
  57. alma/observability/guidelines.py +170 -0
  58. alma/observability/logging.py +424 -424
  59. alma/observability/metrics.py +583 -583
  60. alma/observability/tracing.py +440 -440
  61. alma/progress/__init__.py +21 -21
  62. alma/progress/tracker.py +607 -607
  63. alma/progress/types.py +250 -250
  64. alma/retrieval/__init__.py +134 -53
  65. alma/retrieval/budget.py +525 -0
  66. alma/retrieval/cache.py +1304 -1061
  67. alma/retrieval/embeddings.py +202 -202
  68. alma/retrieval/engine.py +850 -427
  69. alma/retrieval/modes.py +365 -0
  70. alma/retrieval/progressive.py +560 -0
  71. alma/retrieval/scoring.py +344 -344
  72. alma/retrieval/trust_scoring.py +637 -0
  73. alma/retrieval/verification.py +797 -0
  74. alma/session/__init__.py +19 -19
  75. alma/session/manager.py +442 -399
  76. alma/session/types.py +288 -288
  77. alma/storage/__init__.py +101 -90
  78. alma/storage/archive.py +233 -0
  79. alma/storage/azure_cosmos.py +1259 -1259
  80. alma/storage/base.py +1083 -583
  81. alma/storage/chroma.py +1443 -1443
  82. alma/storage/constants.py +103 -103
  83. alma/storage/file_based.py +614 -614
  84. alma/storage/migrations/__init__.py +21 -21
  85. alma/storage/migrations/base.py +321 -321
  86. alma/storage/migrations/runner.py +323 -323
  87. alma/storage/migrations/version_stores.py +337 -337
  88. alma/storage/migrations/versions/__init__.py +11 -11
  89. alma/storage/migrations/versions/v1_0_0.py +373 -373
  90. alma/storage/migrations/versions/v1_1_0_workflow_context.py +551 -0
  91. alma/storage/pinecone.py +1080 -1080
  92. alma/storage/postgresql.py +1948 -1559
  93. alma/storage/qdrant.py +1306 -1306
  94. alma/storage/sqlite_local.py +3041 -1457
  95. alma/testing/__init__.py +46 -46
  96. alma/testing/factories.py +301 -301
  97. alma/testing/mocks.py +389 -389
  98. alma/types.py +292 -264
  99. alma/utils/__init__.py +19 -0
  100. alma/utils/tokenizer.py +521 -0
  101. alma/workflow/__init__.py +83 -0
  102. alma/workflow/artifacts.py +170 -0
  103. alma/workflow/checkpoint.py +311 -0
  104. alma/workflow/context.py +228 -0
  105. alma/workflow/outcomes.py +189 -0
  106. alma/workflow/reducers.py +393 -0
  107. {alma_memory-0.5.1.dist-info → alma_memory-0.7.0.dist-info}/METADATA +210 -72
  108. alma_memory-0.7.0.dist-info/RECORD +112 -0
  109. alma_memory-0.5.1.dist-info/RECORD +0 -93
  110. {alma_memory-0.5.1.dist-info → alma_memory-0.7.0.dist-info}/WHEEL +0 -0
  111. {alma_memory-0.5.1.dist-info → alma_memory-0.7.0.dist-info}/top_level.txt +0 -0
@@ -1,246 +1,246 @@
1
- """
2
- ALMA Event-Aware Storage Mixin.
3
-
4
- Provides event emission capabilities for storage backends.
5
- This is a mixin class that can be used by any storage implementation
6
- to emit events when memory operations occur.
7
- """
8
-
9
- import logging
10
- from dataclasses import asdict
11
- from typing import Any, Dict, Optional
12
-
13
- from alma.events.emitter import EventEmitter, get_emitter
14
- from alma.events.types import MemoryEventType, create_memory_event
15
-
16
- logger = logging.getLogger(__name__)
17
-
18
-
19
- class EventAwareStorageMixin:
20
- """
21
- Mixin that adds event emission to storage backends.
22
-
23
- This mixin provides helper methods to emit events for various
24
- storage operations. Events are only emitted if there are subscribers,
25
- making the overhead negligible when events are not used.
26
-
27
- Usage:
28
- class MyStorage(StorageBackend, EventAwareStorageMixin):
29
- def save_heuristic(self, heuristic):
30
- result_id = super().save_heuristic(heuristic)
31
- self._emit_memory_event(
32
- event_type=MemoryEventType.CREATED,
33
- agent=heuristic.agent,
34
- project_id=heuristic.project_id,
35
- memory_type="heuristics",
36
- memory_id=result_id,
37
- payload=self._heuristic_to_dict(heuristic),
38
- )
39
- return result_id
40
- """
41
-
42
- _events_enabled: bool = True
43
- _custom_emitter: Optional[EventEmitter] = None
44
-
45
- def enable_events(self) -> None:
46
- """Enable event emission for this storage instance."""
47
- self._events_enabled = True
48
-
49
- def disable_events(self) -> None:
50
- """Disable event emission for this storage instance."""
51
- self._events_enabled = False
52
-
53
- def set_emitter(self, emitter: EventEmitter) -> None:
54
- """
55
- Set a custom event emitter for this storage instance.
56
-
57
- Args:
58
- emitter: The event emitter to use
59
- """
60
- self._custom_emitter = emitter
61
-
62
- def _get_emitter(self) -> EventEmitter:
63
- """Get the event emitter to use."""
64
- if self._custom_emitter is not None:
65
- return self._custom_emitter
66
- return get_emitter()
67
-
68
- def _should_emit(self, event_type: MemoryEventType) -> bool:
69
- """
70
- Check if events should be emitted.
71
-
72
- Returns False if:
73
- - Events are disabled for this storage instance
74
- - There are no subscribers for this event type
75
-
76
- This optimization ensures event creation overhead is avoided
77
- when no one is listening.
78
-
79
- Args:
80
- event_type: The type of event being considered
81
-
82
- Returns:
83
- True if an event should be emitted
84
- """
85
- if not self._events_enabled:
86
- return False
87
-
88
- emitter = self._get_emitter()
89
- return emitter.has_subscribers(event_type)
90
-
91
- def _emit_memory_event(
92
- self,
93
- event_type: MemoryEventType,
94
- agent: str,
95
- project_id: str,
96
- memory_type: str,
97
- memory_id: str,
98
- payload: Dict[str, Any],
99
- metadata: Optional[Dict[str, Any]] = None,
100
- ) -> None:
101
- """
102
- Emit a memory event if there are subscribers.
103
-
104
- This is a convenience method that checks for subscribers before
105
- creating and emitting the event.
106
-
107
- Args:
108
- event_type: Type of event
109
- agent: Agent name
110
- project_id: Project identifier
111
- memory_type: Type of memory
112
- memory_id: Memory identifier
113
- payload: Event-specific data
114
- metadata: Optional additional context
115
- """
116
- if not self._should_emit(event_type):
117
- return
118
-
119
- event = create_memory_event(
120
- event_type=event_type,
121
- agent=agent,
122
- project_id=project_id,
123
- memory_type=memory_type,
124
- memory_id=memory_id,
125
- payload=payload,
126
- metadata=metadata,
127
- )
128
-
129
- emitter = self._get_emitter()
130
- emitter.emit(event)
131
-
132
- logger.debug(f"Emitted {event_type.value} for {memory_type}/{memory_id}")
133
-
134
- def _emit_created_event(
135
- self,
136
- agent: str,
137
- project_id: str,
138
- memory_type: str,
139
- memory_id: str,
140
- payload: Dict[str, Any],
141
- ) -> None:
142
- """Emit a CREATED event."""
143
- self._emit_memory_event(
144
- event_type=MemoryEventType.CREATED,
145
- agent=agent,
146
- project_id=project_id,
147
- memory_type=memory_type,
148
- memory_id=memory_id,
149
- payload=payload,
150
- )
151
-
152
- def _emit_updated_event(
153
- self,
154
- agent: str,
155
- project_id: str,
156
- memory_type: str,
157
- memory_id: str,
158
- payload: Dict[str, Any],
159
- ) -> None:
160
- """Emit an UPDATED event."""
161
- self._emit_memory_event(
162
- event_type=MemoryEventType.UPDATED,
163
- agent=agent,
164
- project_id=project_id,
165
- memory_type=memory_type,
166
- memory_id=memory_id,
167
- payload=payload,
168
- )
169
-
170
- def _emit_deleted_event(
171
- self,
172
- agent: str,
173
- project_id: str,
174
- memory_type: str,
175
- memory_id: str,
176
- ) -> None:
177
- """Emit a DELETED event."""
178
- self._emit_memory_event(
179
- event_type=MemoryEventType.DELETED,
180
- agent=agent,
181
- project_id=project_id,
182
- memory_type=memory_type,
183
- memory_id=memory_id,
184
- payload={"deleted_id": memory_id},
185
- )
186
-
187
-
188
- def emit_on_save(
189
- memory_type: str, event_type: MemoryEventType = MemoryEventType.CREATED
190
- ):
191
- """
192
- Decorator to emit events when save methods are called.
193
-
194
- This decorator can be used on storage methods that save memories.
195
- It will emit an event after the save completes successfully.
196
-
197
- Args:
198
- memory_type: The type of memory being saved (e.g., "heuristics")
199
- event_type: The event type to emit (default: CREATED)
200
-
201
- Example:
202
- @emit_on_save("heuristics")
203
- def save_heuristic(self, heuristic: Heuristic) -> str:
204
- # Original implementation
205
- ...
206
- """
207
-
208
- def decorator(func):
209
- def wrapper(self, memory_item):
210
- # Call the original method
211
- result_id = func(self, memory_item)
212
-
213
- # Emit event if storage supports events
214
- if hasattr(self, "_emit_memory_event") and hasattr(self, "_should_emit"):
215
- if self._should_emit(event_type):
216
- # Extract common fields
217
- agent = getattr(memory_item, "agent", "unknown")
218
- project_id = getattr(memory_item, "project_id", "unknown")
219
-
220
- # Convert to dict, handling dataclasses
221
- try:
222
- if hasattr(memory_item, "__dataclass_fields__"):
223
- payload = {
224
- k: v
225
- for k, v in asdict(memory_item).items()
226
- if k != "embedding" # Exclude large embedding vectors
227
- }
228
- else:
229
- payload = {"id": result_id}
230
- except Exception:
231
- payload = {"id": result_id}
232
-
233
- self._emit_memory_event(
234
- event_type=event_type,
235
- agent=agent,
236
- project_id=project_id,
237
- memory_type=memory_type,
238
- memory_id=result_id,
239
- payload=payload,
240
- )
241
-
242
- return result_id
243
-
244
- return wrapper
245
-
246
- return decorator
1
+ """
2
+ ALMA Event-Aware Storage Mixin.
3
+
4
+ Provides event emission capabilities for storage backends.
5
+ This is a mixin class that can be used by any storage implementation
6
+ to emit events when memory operations occur.
7
+ """
8
+
9
+ import logging
10
+ from dataclasses import asdict
11
+ from typing import Any, Dict, Optional
12
+
13
+ from alma.events.emitter import EventEmitter, get_emitter
14
+ from alma.events.types import MemoryEventType, create_memory_event
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+
19
+ class EventAwareStorageMixin:
20
+ """
21
+ Mixin that adds event emission to storage backends.
22
+
23
+ This mixin provides helper methods to emit events for various
24
+ storage operations. Events are only emitted if there are subscribers,
25
+ making the overhead negligible when events are not used.
26
+
27
+ Usage:
28
+ class MyStorage(StorageBackend, EventAwareStorageMixin):
29
+ def save_heuristic(self, heuristic):
30
+ result_id = super().save_heuristic(heuristic)
31
+ self._emit_memory_event(
32
+ event_type=MemoryEventType.CREATED,
33
+ agent=heuristic.agent,
34
+ project_id=heuristic.project_id,
35
+ memory_type="heuristics",
36
+ memory_id=result_id,
37
+ payload=self._heuristic_to_dict(heuristic),
38
+ )
39
+ return result_id
40
+ """
41
+
42
+ _events_enabled: bool = True
43
+ _custom_emitter: Optional[EventEmitter] = None
44
+
45
+ def enable_events(self) -> None:
46
+ """Enable event emission for this storage instance."""
47
+ self._events_enabled = True
48
+
49
+ def disable_events(self) -> None:
50
+ """Disable event emission for this storage instance."""
51
+ self._events_enabled = False
52
+
53
+ def set_emitter(self, emitter: EventEmitter) -> None:
54
+ """
55
+ Set a custom event emitter for this storage instance.
56
+
57
+ Args:
58
+ emitter: The event emitter to use
59
+ """
60
+ self._custom_emitter = emitter
61
+
62
+ def _get_emitter(self) -> EventEmitter:
63
+ """Get the event emitter to use."""
64
+ if self._custom_emitter is not None:
65
+ return self._custom_emitter
66
+ return get_emitter()
67
+
68
+ def _should_emit(self, event_type: MemoryEventType) -> bool:
69
+ """
70
+ Check if events should be emitted.
71
+
72
+ Returns False if:
73
+ - Events are disabled for this storage instance
74
+ - There are no subscribers for this event type
75
+
76
+ This optimization ensures event creation overhead is avoided
77
+ when no one is listening.
78
+
79
+ Args:
80
+ event_type: The type of event being considered
81
+
82
+ Returns:
83
+ True if an event should be emitted
84
+ """
85
+ if not self._events_enabled:
86
+ return False
87
+
88
+ emitter = self._get_emitter()
89
+ return emitter.has_subscribers(event_type)
90
+
91
+ def _emit_memory_event(
92
+ self,
93
+ event_type: MemoryEventType,
94
+ agent: str,
95
+ project_id: str,
96
+ memory_type: str,
97
+ memory_id: str,
98
+ payload: Dict[str, Any],
99
+ metadata: Optional[Dict[str, Any]] = None,
100
+ ) -> None:
101
+ """
102
+ Emit a memory event if there are subscribers.
103
+
104
+ This is a convenience method that checks for subscribers before
105
+ creating and emitting the event.
106
+
107
+ Args:
108
+ event_type: Type of event
109
+ agent: Agent name
110
+ project_id: Project identifier
111
+ memory_type: Type of memory
112
+ memory_id: Memory identifier
113
+ payload: Event-specific data
114
+ metadata: Optional additional context
115
+ """
116
+ if not self._should_emit(event_type):
117
+ return
118
+
119
+ event = create_memory_event(
120
+ event_type=event_type,
121
+ agent=agent,
122
+ project_id=project_id,
123
+ memory_type=memory_type,
124
+ memory_id=memory_id,
125
+ payload=payload,
126
+ metadata=metadata,
127
+ )
128
+
129
+ emitter = self._get_emitter()
130
+ emitter.emit(event)
131
+
132
+ logger.debug(f"Emitted {event_type.value} for {memory_type}/{memory_id}")
133
+
134
+ def _emit_created_event(
135
+ self,
136
+ agent: str,
137
+ project_id: str,
138
+ memory_type: str,
139
+ memory_id: str,
140
+ payload: Dict[str, Any],
141
+ ) -> None:
142
+ """Emit a CREATED event."""
143
+ self._emit_memory_event(
144
+ event_type=MemoryEventType.CREATED,
145
+ agent=agent,
146
+ project_id=project_id,
147
+ memory_type=memory_type,
148
+ memory_id=memory_id,
149
+ payload=payload,
150
+ )
151
+
152
+ def _emit_updated_event(
153
+ self,
154
+ agent: str,
155
+ project_id: str,
156
+ memory_type: str,
157
+ memory_id: str,
158
+ payload: Dict[str, Any],
159
+ ) -> None:
160
+ """Emit an UPDATED event."""
161
+ self._emit_memory_event(
162
+ event_type=MemoryEventType.UPDATED,
163
+ agent=agent,
164
+ project_id=project_id,
165
+ memory_type=memory_type,
166
+ memory_id=memory_id,
167
+ payload=payload,
168
+ )
169
+
170
+ def _emit_deleted_event(
171
+ self,
172
+ agent: str,
173
+ project_id: str,
174
+ memory_type: str,
175
+ memory_id: str,
176
+ ) -> None:
177
+ """Emit a DELETED event."""
178
+ self._emit_memory_event(
179
+ event_type=MemoryEventType.DELETED,
180
+ agent=agent,
181
+ project_id=project_id,
182
+ memory_type=memory_type,
183
+ memory_id=memory_id,
184
+ payload={"deleted_id": memory_id},
185
+ )
186
+
187
+
188
+ def emit_on_save(
189
+ memory_type: str, event_type: MemoryEventType = MemoryEventType.CREATED
190
+ ):
191
+ """
192
+ Decorator to emit events when save methods are called.
193
+
194
+ This decorator can be used on storage methods that save memories.
195
+ It will emit an event after the save completes successfully.
196
+
197
+ Args:
198
+ memory_type: The type of memory being saved (e.g., "heuristics")
199
+ event_type: The event type to emit (default: CREATED)
200
+
201
+ Example:
202
+ @emit_on_save("heuristics")
203
+ def save_heuristic(self, heuristic: Heuristic) -> str:
204
+ # Original implementation
205
+ ...
206
+ """
207
+
208
+ def decorator(func):
209
+ def wrapper(self, memory_item):
210
+ # Call the original method
211
+ result_id = func(self, memory_item)
212
+
213
+ # Emit event if storage supports events
214
+ if hasattr(self, "_emit_memory_event") and hasattr(self, "_should_emit"):
215
+ if self._should_emit(event_type):
216
+ # Extract common fields
217
+ agent = getattr(memory_item, "agent", "unknown")
218
+ project_id = getattr(memory_item, "project_id", "unknown")
219
+
220
+ # Convert to dict, handling dataclasses
221
+ try:
222
+ if hasattr(memory_item, "__dataclass_fields__"):
223
+ payload = {
224
+ k: v
225
+ for k, v in asdict(memory_item).items()
226
+ if k != "embedding" # Exclude large embedding vectors
227
+ }
228
+ else:
229
+ payload = {"id": result_id}
230
+ except Exception:
231
+ payload = {"id": result_id}
232
+
233
+ self._emit_memory_event(
234
+ event_type=event_type,
235
+ agent=agent,
236
+ project_id=project_id,
237
+ memory_type=memory_type,
238
+ memory_id=result_id,
239
+ payload=payload,
240
+ )
241
+
242
+ return result_id
243
+
244
+ return wrapper
245
+
246
+ return decorator