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
@@ -0,0 +1,365 @@
1
+ """
2
+ ALMA Retrieval Modes.
3
+
4
+ Provides mode-aware retrieval strategies that adapt to different cognitive tasks.
5
+ Based on Memory Wall principles: "Planning needs breadth. Execution needs precision."
6
+ """
7
+
8
+ from dataclasses import dataclass, field
9
+ from enum import Enum
10
+ from typing import Dict, List
11
+
12
+
13
+ class RetrievalMode(Enum):
14
+ """
15
+ Cognitive modes for retrieval strategy selection.
16
+
17
+ Different tasks require fundamentally different retrieval approaches:
18
+ - BROAD: For planning, brainstorming - needs diverse, exploratory results
19
+ - PRECISE: For execution, implementation - needs high-confidence matches
20
+ - DIAGNOSTIC: For debugging, troubleshooting - needs anti-patterns and failures
21
+ - LEARNING: For pattern finding, consolidation - needs similar memories to merge
22
+ - RECALL: For exact memory lookup - prioritizes exact matches
23
+ """
24
+
25
+ BROAD = "broad"
26
+ PRECISE = "precise"
27
+ DIAGNOSTIC = "diagnostic"
28
+ LEARNING = "learning"
29
+ RECALL = "recall"
30
+
31
+
32
+ @dataclass
33
+ class ModeConfig:
34
+ """
35
+ Configuration for a retrieval mode.
36
+
37
+ Attributes:
38
+ top_k: Default number of results to return
39
+ min_confidence: Minimum confidence threshold for results
40
+ weights: Scoring weights (similarity, recency, success, confidence)
41
+ include_anti_patterns: Whether to include anti-patterns in results
42
+ diversity_factor: 0.0 = pure relevance, 1.0 = maximum diversity (MMR)
43
+ prioritize_failures: Boost failed outcomes (for debugging)
44
+ cluster_similar: Group similar results together (for learning)
45
+ exact_match_boost: Multiplier for exact/high-similarity matches
46
+ """
47
+
48
+ top_k: int
49
+ min_confidence: float
50
+ weights: Dict[str, float] = field(default_factory=dict)
51
+ include_anti_patterns: bool = True
52
+ diversity_factor: float = 0.0
53
+ prioritize_failures: bool = False
54
+ cluster_similar: bool = False
55
+ exact_match_boost: float = 1.0
56
+
57
+ def __post_init__(self):
58
+ """Validate and normalize weights."""
59
+ if self.weights:
60
+ total = sum(self.weights.values())
61
+ if total > 0 and not (0.99 <= total <= 1.01):
62
+ # Normalize weights to sum to 1.0
63
+ self.weights = {k: v / total for k, v in self.weights.items()}
64
+
65
+
66
+ # Default configurations for each mode
67
+ MODE_CONFIGS: Dict[RetrievalMode, ModeConfig] = {
68
+ RetrievalMode.BROAD: ModeConfig(
69
+ top_k=15,
70
+ min_confidence=0.3,
71
+ weights={
72
+ "similarity": 0.70,
73
+ "recency": 0.10,
74
+ "success_rate": 0.10,
75
+ "confidence": 0.10,
76
+ },
77
+ include_anti_patterns=False, # Exploring, don't want negatives
78
+ diversity_factor=0.8, # High diversity for exploration
79
+ exact_match_boost=1.0,
80
+ ),
81
+ RetrievalMode.PRECISE: ModeConfig(
82
+ top_k=5,
83
+ min_confidence=0.7,
84
+ weights={
85
+ "similarity": 0.30,
86
+ "recency": 0.10,
87
+ "success_rate": 0.40, # Proven strategies matter
88
+ "confidence": 0.20,
89
+ },
90
+ include_anti_patterns=True, # Know what to avoid
91
+ diversity_factor=0.2, # Focused results
92
+ exact_match_boost=2.0, # Boost exact matches
93
+ ),
94
+ RetrievalMode.DIAGNOSTIC: ModeConfig(
95
+ top_k=10,
96
+ min_confidence=0.4,
97
+ weights={
98
+ "similarity": 0.40,
99
+ "recency": 0.30, # Recent issues more relevant
100
+ "success_rate": 0.00, # Don't penalize failures
101
+ "confidence": 0.30,
102
+ },
103
+ include_anti_patterns=True, # Critical for debugging
104
+ diversity_factor=0.5,
105
+ prioritize_failures=True, # Failures are valuable here
106
+ exact_match_boost=1.5,
107
+ ),
108
+ RetrievalMode.LEARNING: ModeConfig(
109
+ top_k=20,
110
+ min_confidence=0.2, # Low threshold to find patterns
111
+ weights={
112
+ "similarity": 0.90, # Similarity is key for consolidation
113
+ "recency": 0.00,
114
+ "success_rate": 0.05,
115
+ "confidence": 0.05,
116
+ },
117
+ include_anti_patterns=True,
118
+ diversity_factor=0.3, # Some diversity but group similar
119
+ cluster_similar=True,
120
+ exact_match_boost=1.0,
121
+ ),
122
+ RetrievalMode.RECALL: ModeConfig(
123
+ top_k=3,
124
+ min_confidence=0.5,
125
+ weights={
126
+ "similarity": 0.95, # Almost pure similarity
127
+ "recency": 0.00,
128
+ "success_rate": 0.00,
129
+ "confidence": 0.05,
130
+ },
131
+ include_anti_patterns=False,
132
+ diversity_factor=0.0, # No diversity, exact match
133
+ exact_match_boost=3.0, # Strong boost for exact matches
134
+ ),
135
+ }
136
+
137
+
138
+ # Keywords for mode inference
139
+ _DIAGNOSTIC_TERMS = frozenset(
140
+ [
141
+ "error",
142
+ "bug",
143
+ "fail",
144
+ "failed",
145
+ "failing",
146
+ "broken",
147
+ "issue",
148
+ "problem",
149
+ "debug",
150
+ "fix",
151
+ "wrong",
152
+ "crash",
153
+ "exception",
154
+ "traceback",
155
+ "not working",
156
+ "doesn't work",
157
+ "won't work",
158
+ "can't",
159
+ ]
160
+ )
161
+
162
+ _BROAD_TERMS = frozenset(
163
+ [
164
+ "how should",
165
+ "what approach",
166
+ "options for",
167
+ "ways to",
168
+ "plan",
169
+ "design",
170
+ "architect",
171
+ "strategy",
172
+ "alternative",
173
+ "consider",
174
+ "brainstorm",
175
+ "explore",
176
+ "ideas for",
177
+ "possibilities",
178
+ ]
179
+ )
180
+
181
+ _RECALL_TERMS = frozenset(
182
+ [
183
+ "what was",
184
+ "when did",
185
+ "remember when",
186
+ "last time",
187
+ "previously",
188
+ "before",
189
+ "earlier",
190
+ "what did we",
191
+ "history of",
192
+ "past",
193
+ ]
194
+ )
195
+
196
+ _LEARNING_TERMS = frozenset(
197
+ [
198
+ "pattern",
199
+ "similar",
200
+ "consolidate",
201
+ "common",
202
+ "recurring",
203
+ "repeated",
204
+ "frequent",
205
+ "trend",
206
+ "consistent",
207
+ "like before",
208
+ ]
209
+ )
210
+
211
+
212
+ def infer_mode_from_query(query: str) -> RetrievalMode:
213
+ """
214
+ Heuristically infer the best retrieval mode from query text.
215
+
216
+ Uses keyword matching to detect the cognitive task type.
217
+ Falls back to PRECISE mode for general queries.
218
+
219
+ Args:
220
+ query: The search query or task description
221
+
222
+ Returns:
223
+ The inferred RetrievalMode
224
+ """
225
+ query_lower = query.lower()
226
+
227
+ # Check for diagnostic terms (errors, bugs, fixes)
228
+ if any(term in query_lower for term in _DIAGNOSTIC_TERMS):
229
+ return RetrievalMode.DIAGNOSTIC
230
+
231
+ # Check for broad/planning terms
232
+ if any(term in query_lower for term in _BROAD_TERMS):
233
+ return RetrievalMode.BROAD
234
+
235
+ # Check for recall terms (historical lookup)
236
+ if any(term in query_lower for term in _RECALL_TERMS):
237
+ return RetrievalMode.RECALL
238
+
239
+ # Check for learning/pattern terms
240
+ if any(term in query_lower for term in _LEARNING_TERMS):
241
+ return RetrievalMode.LEARNING
242
+
243
+ # Default to PRECISE for execution/implementation
244
+ return RetrievalMode.PRECISE
245
+
246
+
247
+ def get_mode_config(mode: RetrievalMode) -> ModeConfig:
248
+ """
249
+ Get the configuration for a specific mode.
250
+
251
+ Args:
252
+ mode: The retrieval mode
253
+
254
+ Returns:
255
+ ModeConfig for the specified mode
256
+ """
257
+ return MODE_CONFIGS[mode]
258
+
259
+
260
+ def get_mode_reason(query: str, mode: RetrievalMode) -> str:
261
+ """
262
+ Explain why a particular mode was inferred.
263
+
264
+ Args:
265
+ query: The original query
266
+ mode: The inferred mode
267
+
268
+ Returns:
269
+ Human-readable explanation
270
+ """
271
+ query_lower = query.lower()
272
+
273
+ if mode == RetrievalMode.DIAGNOSTIC:
274
+ matched = [t for t in _DIAGNOSTIC_TERMS if t in query_lower]
275
+ if matched:
276
+ return f"Query contains diagnostic terms: {', '.join(matched[:3])}"
277
+ return "Query appears to be about debugging or troubleshooting"
278
+
279
+ if mode == RetrievalMode.BROAD:
280
+ matched = [t for t in _BROAD_TERMS if t in query_lower]
281
+ if matched:
282
+ return (
283
+ f"Query contains planning/exploration terms: {', '.join(matched[:3])}"
284
+ )
285
+ return "Query appears to be exploratory or planning-related"
286
+
287
+ if mode == RetrievalMode.RECALL:
288
+ matched = [t for t in _RECALL_TERMS if t in query_lower]
289
+ if matched:
290
+ return f"Query contains recall terms: {', '.join(matched[:3])}"
291
+ return "Query appears to be looking for past events or decisions"
292
+
293
+ if mode == RetrievalMode.LEARNING:
294
+ matched = [t for t in _LEARNING_TERMS if t in query_lower]
295
+ if matched:
296
+ return f"Query contains pattern terms: {', '.join(matched[:3])}"
297
+ return "Query appears to be looking for patterns or similarities"
298
+
299
+ return "Default mode for implementation/execution queries"
300
+
301
+
302
+ def create_custom_mode(base_mode: RetrievalMode, **overrides) -> ModeConfig:
303
+ """
304
+ Create a custom mode configuration based on an existing mode.
305
+
306
+ Args:
307
+ base_mode: The mode to use as a base
308
+ **overrides: Fields to override (top_k, min_confidence, etc.)
309
+
310
+ Returns:
311
+ New ModeConfig with overrides applied
312
+ """
313
+ base = get_mode_config(base_mode)
314
+
315
+ return ModeConfig(
316
+ top_k=overrides.get("top_k", base.top_k),
317
+ min_confidence=overrides.get("min_confidence", base.min_confidence),
318
+ weights=overrides.get("weights", base.weights.copy()),
319
+ include_anti_patterns=overrides.get(
320
+ "include_anti_patterns", base.include_anti_patterns
321
+ ),
322
+ diversity_factor=overrides.get("diversity_factor", base.diversity_factor),
323
+ prioritize_failures=overrides.get(
324
+ "prioritize_failures", base.prioritize_failures
325
+ ),
326
+ cluster_similar=overrides.get("cluster_similar", base.cluster_similar),
327
+ exact_match_boost=overrides.get("exact_match_boost", base.exact_match_boost),
328
+ )
329
+
330
+
331
+ def validate_mode_config(config: ModeConfig) -> List[str]:
332
+ """
333
+ Validate a mode configuration.
334
+
335
+ Args:
336
+ config: The configuration to validate
337
+
338
+ Returns:
339
+ List of validation errors (empty if valid)
340
+ """
341
+ errors = []
342
+
343
+ if config.top_k < 1:
344
+ errors.append("top_k must be at least 1")
345
+
346
+ if not (0.0 <= config.min_confidence <= 1.0):
347
+ errors.append("min_confidence must be between 0.0 and 1.0")
348
+
349
+ if not (0.0 <= config.diversity_factor <= 1.0):
350
+ errors.append("diversity_factor must be between 0.0 and 1.0")
351
+
352
+ if config.exact_match_boost < 0:
353
+ errors.append("exact_match_boost must be non-negative")
354
+
355
+ if config.weights:
356
+ total = sum(config.weights.values())
357
+ if not (0.99 <= total <= 1.01):
358
+ errors.append(f"weights must sum to 1.0 (got {total:.2f})")
359
+
360
+ required_keys = {"similarity", "recency", "success_rate", "confidence"}
361
+ missing = required_keys - set(config.weights.keys())
362
+ if missing:
363
+ errors.append(f"weights missing keys: {missing}")
364
+
365
+ return errors