alma-memory 0.4.0__py3-none-any.whl → 0.5.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.
- alma/__init__.py +88 -44
- alma/confidence/__init__.py +1 -1
- alma/confidence/engine.py +92 -58
- alma/confidence/types.py +34 -14
- alma/config/loader.py +3 -2
- alma/consolidation/__init__.py +23 -0
- alma/consolidation/engine.py +678 -0
- alma/consolidation/prompts.py +84 -0
- alma/core.py +15 -15
- alma/domains/__init__.py +6 -6
- alma/domains/factory.py +12 -9
- alma/domains/schemas.py +17 -3
- alma/domains/types.py +8 -4
- alma/events/__init__.py +75 -0
- alma/events/emitter.py +284 -0
- alma/events/storage_mixin.py +246 -0
- alma/events/types.py +126 -0
- alma/events/webhook.py +425 -0
- alma/exceptions.py +49 -0
- alma/extraction/__init__.py +31 -0
- alma/extraction/auto_learner.py +264 -0
- alma/extraction/extractor.py +420 -0
- alma/graph/__init__.py +81 -0
- alma/graph/backends/__init__.py +18 -0
- alma/graph/backends/memory.py +236 -0
- alma/graph/backends/neo4j.py +417 -0
- alma/graph/base.py +159 -0
- alma/graph/extraction.py +198 -0
- alma/graph/store.py +860 -0
- alma/harness/__init__.py +4 -4
- alma/harness/base.py +18 -9
- alma/harness/domains.py +27 -11
- alma/initializer/__init__.py +1 -1
- alma/initializer/initializer.py +51 -43
- alma/initializer/types.py +25 -17
- alma/integration/__init__.py +9 -9
- alma/integration/claude_agents.py +10 -10
- alma/integration/helena.py +32 -22
- alma/integration/victor.py +57 -33
- alma/learning/__init__.py +27 -27
- alma/learning/forgetting.py +198 -148
- alma/learning/heuristic_extractor.py +40 -24
- alma/learning/protocols.py +62 -14
- alma/learning/validation.py +7 -2
- alma/mcp/__init__.py +4 -4
- alma/mcp/__main__.py +2 -1
- alma/mcp/resources.py +17 -16
- alma/mcp/server.py +102 -44
- alma/mcp/tools.py +174 -37
- alma/progress/__init__.py +3 -3
- alma/progress/tracker.py +26 -20
- alma/progress/types.py +8 -12
- alma/py.typed +0 -0
- alma/retrieval/__init__.py +11 -11
- alma/retrieval/cache.py +20 -21
- alma/retrieval/embeddings.py +4 -4
- alma/retrieval/engine.py +114 -35
- alma/retrieval/scoring.py +73 -63
- alma/session/__init__.py +2 -2
- alma/session/manager.py +5 -5
- alma/session/types.py +5 -4
- alma/storage/__init__.py +41 -0
- alma/storage/azure_cosmos.py +101 -31
- alma/storage/base.py +157 -4
- alma/storage/chroma.py +1443 -0
- alma/storage/file_based.py +56 -20
- alma/storage/pinecone.py +1080 -0
- alma/storage/postgresql.py +1452 -0
- alma/storage/qdrant.py +1306 -0
- alma/storage/sqlite_local.py +376 -31
- alma/types.py +62 -14
- alma_memory-0.5.0.dist-info/METADATA +905 -0
- alma_memory-0.5.0.dist-info/RECORD +76 -0
- {alma_memory-0.4.0.dist-info → alma_memory-0.5.0.dist-info}/WHEEL +1 -1
- alma_memory-0.4.0.dist-info/METADATA +0 -488
- alma_memory-0.4.0.dist-info/RECORD +0 -52
- {alma_memory-0.4.0.dist-info → alma_memory-0.5.0.dist-info}/top_level.txt +0 -0
alma/storage/file_based.py
CHANGED
|
@@ -6,21 +6,19 @@ No vector search - uses basic text matching for retrieval.
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
import json
|
|
9
|
-
import uuid
|
|
10
9
|
import logging
|
|
11
|
-
from pathlib import Path
|
|
12
10
|
from datetime import datetime, timezone
|
|
13
|
-
from
|
|
14
|
-
from
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Any, Dict, List, Optional
|
|
15
13
|
|
|
14
|
+
from alma.storage.base import StorageBackend
|
|
16
15
|
from alma.types import (
|
|
16
|
+
AntiPattern,
|
|
17
|
+
DomainKnowledge,
|
|
17
18
|
Heuristic,
|
|
18
19
|
Outcome,
|
|
19
20
|
UserPreference,
|
|
20
|
-
DomainKnowledge,
|
|
21
|
-
AntiPattern,
|
|
22
21
|
)
|
|
23
|
-
from alma.storage.base import StorageBackend
|
|
24
22
|
|
|
25
23
|
logger = logging.getLogger(__name__)
|
|
26
24
|
|
|
@@ -74,46 +72,86 @@ class FileBasedStorage(StorageBackend):
|
|
|
74
72
|
# ==================== WRITE OPERATIONS ====================
|
|
75
73
|
|
|
76
74
|
def save_heuristic(self, heuristic: Heuristic) -> str:
|
|
77
|
-
"""Save a heuristic."""
|
|
75
|
+
"""Save a heuristic (UPSERT - update if exists, insert if new)."""
|
|
78
76
|
data = self._read_json(self._files["heuristics"])
|
|
79
77
|
record = self._to_dict(heuristic)
|
|
80
|
-
|
|
78
|
+
# Find and replace existing, or append new
|
|
79
|
+
found = False
|
|
80
|
+
for i, existing in enumerate(data):
|
|
81
|
+
if existing.get("id") == record["id"]:
|
|
82
|
+
data[i] = record
|
|
83
|
+
found = True
|
|
84
|
+
break
|
|
85
|
+
if not found:
|
|
86
|
+
data.append(record)
|
|
81
87
|
self._write_json(self._files["heuristics"], data)
|
|
82
88
|
logger.debug(f"Saved heuristic: {heuristic.id}")
|
|
83
89
|
return heuristic.id
|
|
84
90
|
|
|
85
91
|
def save_outcome(self, outcome: Outcome) -> str:
|
|
86
|
-
"""Save an outcome."""
|
|
92
|
+
"""Save an outcome (UPSERT - update if exists, insert if new)."""
|
|
87
93
|
data = self._read_json(self._files["outcomes"])
|
|
88
94
|
record = self._to_dict(outcome)
|
|
89
|
-
|
|
95
|
+
# Find and replace existing, or append new
|
|
96
|
+
found = False
|
|
97
|
+
for i, existing in enumerate(data):
|
|
98
|
+
if existing.get("id") == record["id"]:
|
|
99
|
+
data[i] = record
|
|
100
|
+
found = True
|
|
101
|
+
break
|
|
102
|
+
if not found:
|
|
103
|
+
data.append(record)
|
|
90
104
|
self._write_json(self._files["outcomes"], data)
|
|
91
105
|
logger.debug(f"Saved outcome: {outcome.id}")
|
|
92
106
|
return outcome.id
|
|
93
107
|
|
|
94
108
|
def save_user_preference(self, preference: UserPreference) -> str:
|
|
95
|
-
"""Save a user preference."""
|
|
109
|
+
"""Save a user preference (UPSERT - update if exists, insert if new)."""
|
|
96
110
|
data = self._read_json(self._files["preferences"])
|
|
97
111
|
record = self._to_dict(preference)
|
|
98
|
-
|
|
112
|
+
# Find and replace existing, or append new
|
|
113
|
+
found = False
|
|
114
|
+
for i, existing in enumerate(data):
|
|
115
|
+
if existing.get("id") == record["id"]:
|
|
116
|
+
data[i] = record
|
|
117
|
+
found = True
|
|
118
|
+
break
|
|
119
|
+
if not found:
|
|
120
|
+
data.append(record)
|
|
99
121
|
self._write_json(self._files["preferences"], data)
|
|
100
122
|
logger.debug(f"Saved preference: {preference.id}")
|
|
101
123
|
return preference.id
|
|
102
124
|
|
|
103
125
|
def save_domain_knowledge(self, knowledge: DomainKnowledge) -> str:
|
|
104
|
-
"""Save domain knowledge."""
|
|
126
|
+
"""Save domain knowledge (UPSERT - update if exists, insert if new)."""
|
|
105
127
|
data = self._read_json(self._files["domain_knowledge"])
|
|
106
128
|
record = self._to_dict(knowledge)
|
|
107
|
-
|
|
129
|
+
# Find and replace existing, or append new
|
|
130
|
+
found = False
|
|
131
|
+
for i, existing in enumerate(data):
|
|
132
|
+
if existing.get("id") == record["id"]:
|
|
133
|
+
data[i] = record
|
|
134
|
+
found = True
|
|
135
|
+
break
|
|
136
|
+
if not found:
|
|
137
|
+
data.append(record)
|
|
108
138
|
self._write_json(self._files["domain_knowledge"], data)
|
|
109
139
|
logger.debug(f"Saved domain knowledge: {knowledge.id}")
|
|
110
140
|
return knowledge.id
|
|
111
141
|
|
|
112
142
|
def save_anti_pattern(self, anti_pattern: AntiPattern) -> str:
|
|
113
|
-
"""Save an anti-pattern."""
|
|
143
|
+
"""Save an anti-pattern (UPSERT - update if exists, insert if new)."""
|
|
114
144
|
data = self._read_json(self._files["anti_patterns"])
|
|
115
145
|
record = self._to_dict(anti_pattern)
|
|
116
|
-
|
|
146
|
+
# Find and replace existing, or append new
|
|
147
|
+
found = False
|
|
148
|
+
for i, existing in enumerate(data):
|
|
149
|
+
if existing.get("id") == record["id"]:
|
|
150
|
+
data[i] = record
|
|
151
|
+
found = True
|
|
152
|
+
break
|
|
153
|
+
if not found:
|
|
154
|
+
data.append(record)
|
|
117
155
|
self._write_json(self._files["anti_patterns"], data)
|
|
118
156
|
logger.debug(f"Saved anti-pattern: {anti_pattern.id}")
|
|
119
157
|
return anti_pattern.id
|
|
@@ -451,9 +489,7 @@ class FileBasedStorage(StorageBackend):
|
|
|
451
489
|
count += 1
|
|
452
490
|
stats[f"{name}_count"] = count
|
|
453
491
|
|
|
454
|
-
stats["total_count"] = sum(
|
|
455
|
-
stats[k] for k in stats if k.endswith("_count")
|
|
456
|
-
)
|
|
492
|
+
stats["total_count"] = sum(stats[k] for k in stats if k.endswith("_count"))
|
|
457
493
|
|
|
458
494
|
return stats
|
|
459
495
|
|