alma-memory 0.5.0__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 -194
  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 -322
  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 -264
  24. alma/extraction/extractor.py +420 -420
  25. alma/graph/__init__.py +106 -81
  26. alma/graph/backends/__init__.py +32 -18
  27. alma/graph/backends/kuzu.py +624 -0
  28. alma/graph/backends/memgraph.py +432 -0
  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 -432
  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 -511
  55. alma/observability/__init__.py +91 -0
  56. alma/observability/config.py +302 -0
  57. alma/observability/guidelines.py +170 -0
  58. alma/observability/logging.py +424 -0
  59. alma/observability/metrics.py +583 -0
  60. alma/observability/tracing.py +440 -0
  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 -366
  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 -61
  78. alma/storage/archive.py +233 -0
  79. alma/storage/azure_cosmos.py +1259 -1048
  80. alma/storage/base.py +1083 -525
  81. alma/storage/chroma.py +1443 -1443
  82. alma/storage/constants.py +103 -0
  83. alma/storage/file_based.py +614 -619
  84. alma/storage/migrations/__init__.py +21 -0
  85. alma/storage/migrations/base.py +321 -0
  86. alma/storage/migrations/runner.py +323 -0
  87. alma/storage/migrations/version_stores.py +337 -0
  88. alma/storage/migrations/versions/__init__.py +11 -0
  89. alma/storage/migrations/versions/v1_0_0.py +373 -0
  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 -1452
  93. alma/storage/qdrant.py +1306 -1306
  94. alma/storage/sqlite_local.py +3041 -1358
  95. alma/testing/__init__.py +46 -0
  96. alma/testing/factories.py +301 -0
  97. alma/testing/mocks.py +389 -0
  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.0.dist-info → alma_memory-0.7.0.dist-info}/METADATA +244 -72
  108. alma_memory-0.7.0.dist-info/RECORD +112 -0
  109. alma_memory-0.5.0.dist-info/RECORD +0 -76
  110. {alma_memory-0.5.0.dist-info → alma_memory-0.7.0.dist-info}/WHEEL +0 -0
  111. {alma_memory-0.5.0.dist-info → alma_memory-0.7.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,373 @@
1
+ """
2
+ ALMA Schema Migration v1.0.0 - Initial Schema.
3
+
4
+ This migration establishes the baseline schema for existing databases.
5
+ For fresh installations, this creates the initial tables.
6
+ For existing databases, this records the current state.
7
+ """
8
+
9
+ from typing import Any
10
+
11
+ from alma.storage.migrations.base import Migration, register_migration
12
+
13
+
14
+ @register_migration(backend="sqlite")
15
+ class SQLiteInitialSchema(Migration):
16
+ """
17
+ SQLite initial schema migration.
18
+
19
+ This represents the baseline schema as of ALMA v0.5.x.
20
+ For existing databases, this is a no-op that records the baseline.
21
+ """
22
+
23
+ version = "1.0.0"
24
+ description = "Initial ALMA schema with core tables"
25
+
26
+ def upgrade(self, connection: Any) -> None:
27
+ """
28
+ Create or verify initial schema.
29
+
30
+ For SQLite, this creates all core tables if they don't exist.
31
+ """
32
+ cursor = connection.cursor()
33
+
34
+ # Heuristics table
35
+ cursor.execute("""
36
+ CREATE TABLE IF NOT EXISTS heuristics (
37
+ id TEXT PRIMARY KEY,
38
+ agent TEXT NOT NULL,
39
+ project_id TEXT NOT NULL,
40
+ condition TEXT NOT NULL,
41
+ strategy TEXT NOT NULL,
42
+ confidence REAL DEFAULT 0.0,
43
+ occurrence_count INTEGER DEFAULT 0,
44
+ success_count INTEGER DEFAULT 0,
45
+ last_validated TEXT,
46
+ created_at TEXT,
47
+ metadata TEXT
48
+ )
49
+ """)
50
+ cursor.execute(
51
+ "CREATE INDEX IF NOT EXISTS idx_heuristics_project_agent "
52
+ "ON heuristics(project_id, agent)"
53
+ )
54
+
55
+ # Outcomes table
56
+ cursor.execute("""
57
+ CREATE TABLE IF NOT EXISTS outcomes (
58
+ id TEXT PRIMARY KEY,
59
+ agent TEXT NOT NULL,
60
+ project_id TEXT NOT NULL,
61
+ task_type TEXT,
62
+ task_description TEXT NOT NULL,
63
+ success INTEGER DEFAULT 0,
64
+ strategy_used TEXT,
65
+ duration_ms INTEGER,
66
+ error_message TEXT,
67
+ user_feedback TEXT,
68
+ timestamp TEXT,
69
+ metadata TEXT
70
+ )
71
+ """)
72
+ cursor.execute(
73
+ "CREATE INDEX IF NOT EXISTS idx_outcomes_project_agent "
74
+ "ON outcomes(project_id, agent)"
75
+ )
76
+ cursor.execute(
77
+ "CREATE INDEX IF NOT EXISTS idx_outcomes_task_type "
78
+ "ON outcomes(project_id, agent, task_type)"
79
+ )
80
+ cursor.execute(
81
+ "CREATE INDEX IF NOT EXISTS idx_outcomes_timestamp "
82
+ "ON outcomes(project_id, timestamp)"
83
+ )
84
+
85
+ # User preferences table
86
+ cursor.execute("""
87
+ CREATE TABLE IF NOT EXISTS preferences (
88
+ id TEXT PRIMARY KEY,
89
+ user_id TEXT NOT NULL,
90
+ category TEXT,
91
+ preference TEXT NOT NULL,
92
+ source TEXT,
93
+ confidence REAL DEFAULT 1.0,
94
+ timestamp TEXT,
95
+ metadata TEXT
96
+ )
97
+ """)
98
+ cursor.execute(
99
+ "CREATE INDEX IF NOT EXISTS idx_preferences_user ON preferences(user_id)"
100
+ )
101
+
102
+ # Domain knowledge table
103
+ cursor.execute("""
104
+ CREATE TABLE IF NOT EXISTS domain_knowledge (
105
+ id TEXT PRIMARY KEY,
106
+ agent TEXT NOT NULL,
107
+ project_id TEXT NOT NULL,
108
+ domain TEXT,
109
+ fact TEXT NOT NULL,
110
+ source TEXT,
111
+ confidence REAL DEFAULT 1.0,
112
+ last_verified TEXT,
113
+ metadata TEXT
114
+ )
115
+ """)
116
+ cursor.execute(
117
+ "CREATE INDEX IF NOT EXISTS idx_domain_knowledge_project_agent "
118
+ "ON domain_knowledge(project_id, agent)"
119
+ )
120
+
121
+ # Anti-patterns table
122
+ cursor.execute("""
123
+ CREATE TABLE IF NOT EXISTS anti_patterns (
124
+ id TEXT PRIMARY KEY,
125
+ agent TEXT NOT NULL,
126
+ project_id TEXT NOT NULL,
127
+ pattern TEXT NOT NULL,
128
+ why_bad TEXT,
129
+ better_alternative TEXT,
130
+ occurrence_count INTEGER DEFAULT 1,
131
+ last_seen TEXT,
132
+ created_at TEXT,
133
+ metadata TEXT
134
+ )
135
+ """)
136
+ cursor.execute(
137
+ "CREATE INDEX IF NOT EXISTS idx_anti_patterns_project_agent "
138
+ "ON anti_patterns(project_id, agent)"
139
+ )
140
+
141
+ # Embeddings table
142
+ cursor.execute("""
143
+ CREATE TABLE IF NOT EXISTS embeddings (
144
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
145
+ memory_type TEXT NOT NULL,
146
+ memory_id TEXT NOT NULL,
147
+ embedding BLOB NOT NULL,
148
+ UNIQUE(memory_type, memory_id)
149
+ )
150
+ """)
151
+ cursor.execute(
152
+ "CREATE INDEX IF NOT EXISTS idx_embeddings_type ON embeddings(memory_type)"
153
+ )
154
+
155
+ connection.commit()
156
+
157
+ def downgrade(self, connection: Any) -> None:
158
+ """
159
+ Downgrade is not supported for initial schema.
160
+
161
+ Rolling back the initial schema would destroy all data.
162
+ """
163
+ raise NotImplementedError(
164
+ "Cannot roll back initial schema - this would destroy all data"
165
+ )
166
+
167
+ def pre_check(self, connection: Any) -> bool:
168
+ """Verify we can connect to the database."""
169
+ try:
170
+ cursor = connection.cursor()
171
+ cursor.execute("SELECT 1")
172
+ return True
173
+ except Exception:
174
+ return False
175
+
176
+
177
+ @register_migration(backend="postgresql")
178
+ class PostgreSQLInitialSchema(Migration):
179
+ """
180
+ PostgreSQL initial schema migration.
181
+
182
+ This represents the baseline schema as of ALMA v0.5.x.
183
+ """
184
+
185
+ version = "1.0.0"
186
+ description = "Initial ALMA schema with core tables and pgvector support"
187
+
188
+ def __init__(self, schema: str = "public", embedding_dim: int = 384):
189
+ self._schema = schema
190
+ self._embedding_dim = embedding_dim
191
+
192
+ def upgrade(self, connection: Any) -> None:
193
+ """Create or verify initial PostgreSQL schema."""
194
+ schema = self._schema
195
+ embedding_dim = self._embedding_dim
196
+
197
+ # Try to enable pgvector
198
+ pgvector_available = False
199
+ try:
200
+ connection.execute("CREATE EXTENSION IF NOT EXISTS vector")
201
+ connection.commit()
202
+ pgvector_available = True
203
+ except Exception:
204
+ connection.rollback()
205
+
206
+ vector_type = f"VECTOR({embedding_dim})" if pgvector_available else "BYTEA"
207
+
208
+ # Heuristics table
209
+ connection.execute(f"""
210
+ CREATE TABLE IF NOT EXISTS {schema}.alma_heuristics (
211
+ id TEXT PRIMARY KEY,
212
+ agent TEXT NOT NULL,
213
+ project_id TEXT NOT NULL,
214
+ condition TEXT NOT NULL,
215
+ strategy TEXT NOT NULL,
216
+ confidence REAL DEFAULT 0.0,
217
+ occurrence_count INTEGER DEFAULT 0,
218
+ success_count INTEGER DEFAULT 0,
219
+ last_validated TIMESTAMPTZ,
220
+ created_at TIMESTAMPTZ DEFAULT NOW(),
221
+ metadata JSONB,
222
+ embedding {vector_type}
223
+ )
224
+ """)
225
+ connection.execute(f"""
226
+ CREATE INDEX IF NOT EXISTS idx_heuristics_project_agent
227
+ ON {schema}.alma_heuristics(project_id, agent)
228
+ """)
229
+ connection.execute(f"""
230
+ CREATE INDEX IF NOT EXISTS idx_heuristics_confidence
231
+ ON {schema}.alma_heuristics(project_id, confidence DESC)
232
+ """)
233
+
234
+ # Outcomes table
235
+ connection.execute(f"""
236
+ CREATE TABLE IF NOT EXISTS {schema}.alma_outcomes (
237
+ id TEXT PRIMARY KEY,
238
+ agent TEXT NOT NULL,
239
+ project_id TEXT NOT NULL,
240
+ task_type TEXT,
241
+ task_description TEXT NOT NULL,
242
+ success BOOLEAN DEFAULT FALSE,
243
+ strategy_used TEXT,
244
+ duration_ms INTEGER,
245
+ error_message TEXT,
246
+ user_feedback TEXT,
247
+ timestamp TIMESTAMPTZ DEFAULT NOW(),
248
+ metadata JSONB,
249
+ embedding {vector_type}
250
+ )
251
+ """)
252
+ connection.execute(f"""
253
+ CREATE INDEX IF NOT EXISTS idx_outcomes_project_agent
254
+ ON {schema}.alma_outcomes(project_id, agent)
255
+ """)
256
+ connection.execute(f"""
257
+ CREATE INDEX IF NOT EXISTS idx_outcomes_task_type
258
+ ON {schema}.alma_outcomes(project_id, agent, task_type)
259
+ """)
260
+ connection.execute(f"""
261
+ CREATE INDEX IF NOT EXISTS idx_outcomes_timestamp
262
+ ON {schema}.alma_outcomes(project_id, timestamp DESC)
263
+ """)
264
+
265
+ # User preferences table
266
+ connection.execute(f"""
267
+ CREATE TABLE IF NOT EXISTS {schema}.alma_preferences (
268
+ id TEXT PRIMARY KEY,
269
+ user_id TEXT NOT NULL,
270
+ category TEXT,
271
+ preference TEXT NOT NULL,
272
+ source TEXT,
273
+ confidence REAL DEFAULT 1.0,
274
+ timestamp TIMESTAMPTZ DEFAULT NOW(),
275
+ metadata JSONB
276
+ )
277
+ """)
278
+ connection.execute(f"""
279
+ CREATE INDEX IF NOT EXISTS idx_preferences_user
280
+ ON {schema}.alma_preferences(user_id)
281
+ """)
282
+
283
+ # Domain knowledge table
284
+ connection.execute(f"""
285
+ CREATE TABLE IF NOT EXISTS {schema}.alma_domain_knowledge (
286
+ id TEXT PRIMARY KEY,
287
+ agent TEXT NOT NULL,
288
+ project_id TEXT NOT NULL,
289
+ domain TEXT,
290
+ fact TEXT NOT NULL,
291
+ source TEXT,
292
+ confidence REAL DEFAULT 1.0,
293
+ last_verified TIMESTAMPTZ DEFAULT NOW(),
294
+ metadata JSONB,
295
+ embedding {vector_type}
296
+ )
297
+ """)
298
+ connection.execute(f"""
299
+ CREATE INDEX IF NOT EXISTS idx_domain_knowledge_project_agent
300
+ ON {schema}.alma_domain_knowledge(project_id, agent)
301
+ """)
302
+ connection.execute(f"""
303
+ CREATE INDEX IF NOT EXISTS idx_domain_knowledge_confidence
304
+ ON {schema}.alma_domain_knowledge(project_id, confidence DESC)
305
+ """)
306
+
307
+ # Anti-patterns table
308
+ connection.execute(f"""
309
+ CREATE TABLE IF NOT EXISTS {schema}.alma_anti_patterns (
310
+ id TEXT PRIMARY KEY,
311
+ agent TEXT NOT NULL,
312
+ project_id TEXT NOT NULL,
313
+ pattern TEXT NOT NULL,
314
+ why_bad TEXT,
315
+ better_alternative TEXT,
316
+ occurrence_count INTEGER DEFAULT 1,
317
+ last_seen TIMESTAMPTZ DEFAULT NOW(),
318
+ created_at TIMESTAMPTZ DEFAULT NOW(),
319
+ metadata JSONB,
320
+ embedding {vector_type}
321
+ )
322
+ """)
323
+ connection.execute(f"""
324
+ CREATE INDEX IF NOT EXISTS idx_anti_patterns_project_agent
325
+ ON {schema}.alma_anti_patterns(project_id, agent)
326
+ """)
327
+
328
+ # Create vector indexes if pgvector available
329
+ if pgvector_available:
330
+ for table in [
331
+ "alma_heuristics",
332
+ "alma_outcomes",
333
+ "alma_domain_knowledge",
334
+ "alma_anti_patterns",
335
+ ]:
336
+ try:
337
+ connection.execute(f"""
338
+ CREATE INDEX IF NOT EXISTS idx_{table}_embedding
339
+ ON {schema}.{table}
340
+ USING hnsw (embedding vector_cosine_ops)
341
+ WITH (m = 16, ef_construction = 64)
342
+ """)
343
+ except Exception:
344
+ pass # Index may already exist or not be possible
345
+
346
+ connection.commit()
347
+
348
+ def downgrade(self, connection: Any) -> None:
349
+ """Cannot roll back initial schema."""
350
+ raise NotImplementedError(
351
+ "Cannot roll back initial schema - this would destroy all data"
352
+ )
353
+
354
+
355
+ @register_migration()
356
+ class FileBasedInitialSchema(Migration):
357
+ """
358
+ File-based storage initial schema migration.
359
+
360
+ This is mostly a no-op since file-based storage creates files on demand.
361
+ """
362
+
363
+ version = "1.0.0"
364
+ description = "Initial ALMA file-based storage schema"
365
+
366
+ def upgrade(self, storage: Any) -> None:
367
+ """Verify file-based storage is properly initialized."""
368
+ # File-based storage creates files on demand, so this is a no-op
369
+ pass
370
+
371
+ def downgrade(self, storage: Any) -> None:
372
+ """Cannot roll back initial schema."""
373
+ raise NotImplementedError("Cannot roll back initial schema")