alma-memory 0.2.0__py3-none-any.whl → 0.4.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 +76 -1
- alma/confidence/__init__.py +47 -0
- alma/confidence/engine.py +506 -0
- alma/confidence/types.py +331 -0
- alma/domains/__init__.py +30 -0
- alma/domains/factory.py +356 -0
- alma/domains/schemas.py +434 -0
- alma/domains/types.py +268 -0
- alma/initializer/__init__.py +37 -0
- alma/initializer/initializer.py +410 -0
- alma/initializer/types.py +242 -0
- alma/progress/__init__.py +21 -0
- alma/progress/tracker.py +601 -0
- alma/progress/types.py +254 -0
- alma/session/__init__.py +19 -0
- alma/session/manager.py +399 -0
- alma/session/types.py +287 -0
- alma/storage/azure_cosmos.py +6 -0
- alma/storage/sqlite_local.py +101 -0
- alma_memory-0.4.0.dist-info/METADATA +488 -0
- {alma_memory-0.2.0.dist-info → alma_memory-0.4.0.dist-info}/RECORD +23 -7
- alma_memory-0.2.0.dist-info/METADATA +0 -327
- {alma_memory-0.2.0.dist-info → alma_memory-0.4.0.dist-info}/WHEEL +0 -0
- {alma_memory-0.2.0.dist-info → alma_memory-0.4.0.dist-info}/top_level.txt +0 -0
alma/domains/factory.py
ADDED
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Domain Memory Factory.
|
|
3
|
+
|
|
4
|
+
Factory pattern for creating domain-specific ALMA instances.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Dict, Any, Optional, List, Type
|
|
8
|
+
import logging
|
|
9
|
+
|
|
10
|
+
from alma.domains.types import DomainSchema, EntityType, RelationshipType
|
|
11
|
+
from alma.domains.schemas import (
|
|
12
|
+
get_coding_schema,
|
|
13
|
+
get_research_schema,
|
|
14
|
+
get_sales_schema,
|
|
15
|
+
get_general_schema,
|
|
16
|
+
get_customer_support_schema,
|
|
17
|
+
get_content_creation_schema,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
logger = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class DomainMemoryFactory:
|
|
24
|
+
"""
|
|
25
|
+
Factory for creating domain-specific ALMA instances.
|
|
26
|
+
|
|
27
|
+
Provides:
|
|
28
|
+
- Pre-built schemas for common domains
|
|
29
|
+
- Custom schema creation from config
|
|
30
|
+
- ALMA instance creation with domain-specific settings
|
|
31
|
+
|
|
32
|
+
Usage:
|
|
33
|
+
# Use pre-built schema
|
|
34
|
+
factory = DomainMemoryFactory()
|
|
35
|
+
schema = factory.get_schema("coding")
|
|
36
|
+
alma = factory.create_alma(schema, "my-project", storage)
|
|
37
|
+
|
|
38
|
+
# Create custom schema
|
|
39
|
+
schema = factory.create_schema("my-domain", {
|
|
40
|
+
"description": "Custom domain",
|
|
41
|
+
"entity_types": [...],
|
|
42
|
+
"learning_categories": [...]
|
|
43
|
+
})
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
# Registry of pre-built schemas
|
|
47
|
+
_builtin_schemas: Dict[str, callable] = {
|
|
48
|
+
"coding": get_coding_schema,
|
|
49
|
+
"research": get_research_schema,
|
|
50
|
+
"sales": get_sales_schema,
|
|
51
|
+
"general": get_general_schema,
|
|
52
|
+
"customer_support": get_customer_support_schema,
|
|
53
|
+
"content_creation": get_content_creation_schema,
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
# Custom schema registry (for user-defined schemas)
|
|
57
|
+
_custom_schemas: Dict[str, DomainSchema] = {}
|
|
58
|
+
|
|
59
|
+
def __init__(self):
|
|
60
|
+
"""Initialize the factory."""
|
|
61
|
+
pass
|
|
62
|
+
|
|
63
|
+
@classmethod
|
|
64
|
+
def list_schemas(cls) -> List[str]:
|
|
65
|
+
"""List all available schema names (built-in and custom)."""
|
|
66
|
+
return list(cls._builtin_schemas.keys()) + list(cls._custom_schemas.keys())
|
|
67
|
+
|
|
68
|
+
@classmethod
|
|
69
|
+
def get_schema(cls, name: str) -> Optional[DomainSchema]:
|
|
70
|
+
"""
|
|
71
|
+
Get a schema by name.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
name: Schema name (e.g., "coding", "research")
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
DomainSchema or None if not found
|
|
78
|
+
"""
|
|
79
|
+
# Check custom schemas first
|
|
80
|
+
if name in cls._custom_schemas:
|
|
81
|
+
return cls._custom_schemas[name]
|
|
82
|
+
|
|
83
|
+
# Check built-in schemas
|
|
84
|
+
if name in cls._builtin_schemas:
|
|
85
|
+
return cls._builtin_schemas[name]()
|
|
86
|
+
|
|
87
|
+
return None
|
|
88
|
+
|
|
89
|
+
@classmethod
|
|
90
|
+
def create_schema(
|
|
91
|
+
cls,
|
|
92
|
+
name: str,
|
|
93
|
+
config: Dict[str, Any],
|
|
94
|
+
register: bool = True,
|
|
95
|
+
) -> DomainSchema:
|
|
96
|
+
"""
|
|
97
|
+
Create a new domain schema from configuration.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
name: Schema name
|
|
101
|
+
config: Schema configuration dictionary
|
|
102
|
+
register: If True, register schema for later retrieval
|
|
103
|
+
|
|
104
|
+
Config format:
|
|
105
|
+
{
|
|
106
|
+
"description": "Schema description",
|
|
107
|
+
"entity_types": [
|
|
108
|
+
{"name": "entity1", "description": "...", "attributes": ["a", "b"]}
|
|
109
|
+
],
|
|
110
|
+
"relationship_types": [
|
|
111
|
+
{"name": "rel1", "description": "...", "source": "e1", "target": "e2"}
|
|
112
|
+
],
|
|
113
|
+
"learning_categories": ["cat1", "cat2"],
|
|
114
|
+
"excluded_categories": ["cat3"],
|
|
115
|
+
"min_occurrences_for_heuristic": 3,
|
|
116
|
+
"confidence_decay_days": 30.0
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
Created DomainSchema
|
|
121
|
+
"""
|
|
122
|
+
schema = DomainSchema.create(
|
|
123
|
+
name=name,
|
|
124
|
+
description=config.get("description", f"Custom schema: {name}"),
|
|
125
|
+
learning_categories=config.get("learning_categories", []),
|
|
126
|
+
excluded_categories=config.get("excluded_categories", []),
|
|
127
|
+
min_occurrences_for_heuristic=config.get("min_occurrences_for_heuristic", 3),
|
|
128
|
+
confidence_decay_days=config.get("confidence_decay_days", 30.0),
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
# Add entity types
|
|
132
|
+
for entity_config in config.get("entity_types", []):
|
|
133
|
+
schema.add_entity_type(
|
|
134
|
+
name=entity_config["name"],
|
|
135
|
+
description=entity_config.get("description", ""),
|
|
136
|
+
attributes=entity_config.get("attributes", []),
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
# Add relationship types
|
|
140
|
+
for rel_config in config.get("relationship_types", []):
|
|
141
|
+
schema.add_relationship_type(
|
|
142
|
+
name=rel_config["name"],
|
|
143
|
+
description=rel_config.get("description", ""),
|
|
144
|
+
source_type=rel_config.get("source_type", rel_config.get("source", "")),
|
|
145
|
+
target_type=rel_config.get("target_type", rel_config.get("target", "")),
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
# Validate
|
|
149
|
+
errors = schema.validate()
|
|
150
|
+
if errors:
|
|
151
|
+
logger.warning(f"Schema validation warnings for '{name}': {errors}")
|
|
152
|
+
|
|
153
|
+
# Register if requested
|
|
154
|
+
if register:
|
|
155
|
+
cls._custom_schemas[name] = schema
|
|
156
|
+
logger.info(f"Registered custom schema: {name}")
|
|
157
|
+
|
|
158
|
+
return schema
|
|
159
|
+
|
|
160
|
+
@classmethod
|
|
161
|
+
def register_schema(cls, schema: DomainSchema) -> None:
|
|
162
|
+
"""Register an existing schema for later retrieval."""
|
|
163
|
+
cls._custom_schemas[schema.name] = schema
|
|
164
|
+
logger.info(f"Registered schema: {schema.name}")
|
|
165
|
+
|
|
166
|
+
@classmethod
|
|
167
|
+
def unregister_schema(cls, name: str) -> bool:
|
|
168
|
+
"""Unregister a custom schema."""
|
|
169
|
+
if name in cls._custom_schemas:
|
|
170
|
+
del cls._custom_schemas[name]
|
|
171
|
+
return True
|
|
172
|
+
return False
|
|
173
|
+
|
|
174
|
+
def create_alma(
|
|
175
|
+
self,
|
|
176
|
+
schema: DomainSchema,
|
|
177
|
+
project_id: str,
|
|
178
|
+
storage: Optional[Any] = None,
|
|
179
|
+
embedding_provider: str = "mock",
|
|
180
|
+
**config,
|
|
181
|
+
) -> Any:
|
|
182
|
+
"""
|
|
183
|
+
Create ALMA instance configured for a domain.
|
|
184
|
+
|
|
185
|
+
Args:
|
|
186
|
+
schema: Domain schema to use
|
|
187
|
+
project_id: Project identifier
|
|
188
|
+
storage: Optional storage backend (FileBasedStorage created if None)
|
|
189
|
+
embedding_provider: Embedding provider ("mock", "local", "openai")
|
|
190
|
+
**config: Additional ALMA configuration
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
Configured ALMA instance
|
|
194
|
+
|
|
195
|
+
Note:
|
|
196
|
+
This integrates with the core ALMA class.
|
|
197
|
+
The schema is used to:
|
|
198
|
+
- Configure allowed learning categories
|
|
199
|
+
- Set heuristic thresholds
|
|
200
|
+
- Initialize domain-specific entity tracking
|
|
201
|
+
"""
|
|
202
|
+
# Import here to avoid circular dependency
|
|
203
|
+
from alma.storage.file_based import FileBasedStorage
|
|
204
|
+
from alma.retrieval import RetrievalEngine
|
|
205
|
+
from alma.learning import LearningProtocol
|
|
206
|
+
from alma.types import MemoryScope
|
|
207
|
+
from alma import ALMA
|
|
208
|
+
|
|
209
|
+
# Create storage if not provided
|
|
210
|
+
if storage is None:
|
|
211
|
+
import tempfile
|
|
212
|
+
from pathlib import Path
|
|
213
|
+
storage_dir = Path(tempfile.mkdtemp()) / ".alma" / project_id
|
|
214
|
+
storage = FileBasedStorage(storage_dir)
|
|
215
|
+
|
|
216
|
+
# Create retrieval engine
|
|
217
|
+
retrieval = RetrievalEngine(
|
|
218
|
+
storage=storage,
|
|
219
|
+
embedding_provider=embedding_provider,
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
# Create scope based on schema
|
|
223
|
+
default_agent = config.get("default_agent", "agent")
|
|
224
|
+
scopes = {
|
|
225
|
+
default_agent: MemoryScope(
|
|
226
|
+
agent_name=default_agent,
|
|
227
|
+
can_learn=schema.learning_categories,
|
|
228
|
+
cannot_learn=schema.excluded_categories,
|
|
229
|
+
min_occurrences_for_heuristic=schema.min_occurrences_for_heuristic,
|
|
230
|
+
)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
# Create learning protocol
|
|
234
|
+
learning = LearningProtocol(
|
|
235
|
+
storage=storage,
|
|
236
|
+
scopes=scopes,
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
# Create ALMA instance
|
|
240
|
+
alma = ALMA(
|
|
241
|
+
storage=storage,
|
|
242
|
+
retrieval_engine=retrieval,
|
|
243
|
+
learning_protocol=learning,
|
|
244
|
+
scopes=scopes,
|
|
245
|
+
project_id=project_id,
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
# Store schema reference for domain-aware operations
|
|
249
|
+
alma._domain_schema = schema
|
|
250
|
+
|
|
251
|
+
logger.info(
|
|
252
|
+
f"Created ALMA instance for project '{project_id}' "
|
|
253
|
+
f"with domain schema '{schema.name}'"
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
return alma
|
|
257
|
+
|
|
258
|
+
def create_alma_for_agent(
|
|
259
|
+
self,
|
|
260
|
+
schema_name: str,
|
|
261
|
+
agent: str,
|
|
262
|
+
project_id: str,
|
|
263
|
+
storage: Optional[Any] = None,
|
|
264
|
+
scope_restrictions: Optional[List[str]] = None,
|
|
265
|
+
**config,
|
|
266
|
+
) -> Any:
|
|
267
|
+
"""
|
|
268
|
+
Create ALMA instance for a specific agent.
|
|
269
|
+
|
|
270
|
+
This is a convenience method that:
|
|
271
|
+
1. Gets the appropriate schema
|
|
272
|
+
2. Creates ALMA instance
|
|
273
|
+
3. Configures agent-specific settings
|
|
274
|
+
|
|
275
|
+
Args:
|
|
276
|
+
schema_name: Name of schema to use
|
|
277
|
+
agent: Agent identifier
|
|
278
|
+
project_id: Project identifier
|
|
279
|
+
storage: Optional storage backend
|
|
280
|
+
scope_restrictions: Categories agent cannot learn from
|
|
281
|
+
**config: Additional ALMA configuration
|
|
282
|
+
|
|
283
|
+
Returns:
|
|
284
|
+
Configured ALMA instance for the agent
|
|
285
|
+
"""
|
|
286
|
+
schema = self.get_schema(schema_name)
|
|
287
|
+
if not schema:
|
|
288
|
+
raise ValueError(f"Unknown schema: {schema_name}")
|
|
289
|
+
|
|
290
|
+
# Apply scope restrictions
|
|
291
|
+
if scope_restrictions:
|
|
292
|
+
for cat in scope_restrictions:
|
|
293
|
+
schema.add_excluded_category(cat)
|
|
294
|
+
|
|
295
|
+
# Create ALMA with agent config
|
|
296
|
+
alma = self.create_alma(
|
|
297
|
+
schema=schema,
|
|
298
|
+
project_id=project_id,
|
|
299
|
+
storage=storage,
|
|
300
|
+
default_agent=agent,
|
|
301
|
+
**config,
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
return alma
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
# Convenience functions for common patterns
|
|
308
|
+
def create_coding_alma(
|
|
309
|
+
project_id: str,
|
|
310
|
+
agent: str = "developer",
|
|
311
|
+
storage: Optional[Any] = None,
|
|
312
|
+
**config,
|
|
313
|
+
) -> Any:
|
|
314
|
+
"""Create ALMA configured for coding workflows."""
|
|
315
|
+
factory = DomainMemoryFactory()
|
|
316
|
+
return factory.create_alma_for_agent(
|
|
317
|
+
schema_name="coding",
|
|
318
|
+
agent=agent,
|
|
319
|
+
project_id=project_id,
|
|
320
|
+
storage=storage,
|
|
321
|
+
**config,
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
def create_research_alma(
|
|
326
|
+
project_id: str,
|
|
327
|
+
agent: str = "researcher",
|
|
328
|
+
storage: Optional[Any] = None,
|
|
329
|
+
**config,
|
|
330
|
+
) -> Any:
|
|
331
|
+
"""Create ALMA configured for research workflows."""
|
|
332
|
+
factory = DomainMemoryFactory()
|
|
333
|
+
return factory.create_alma_for_agent(
|
|
334
|
+
schema_name="research",
|
|
335
|
+
agent=agent,
|
|
336
|
+
project_id=project_id,
|
|
337
|
+
storage=storage,
|
|
338
|
+
**config,
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def create_general_alma(
|
|
343
|
+
project_id: str,
|
|
344
|
+
agent: str = "assistant",
|
|
345
|
+
storage: Optional[Any] = None,
|
|
346
|
+
**config,
|
|
347
|
+
) -> Any:
|
|
348
|
+
"""Create ALMA configured for general-purpose agents."""
|
|
349
|
+
factory = DomainMemoryFactory()
|
|
350
|
+
return factory.create_alma_for_agent(
|
|
351
|
+
schema_name="general",
|
|
352
|
+
agent=agent,
|
|
353
|
+
project_id=project_id,
|
|
354
|
+
storage=storage,
|
|
355
|
+
**config,
|
|
356
|
+
)
|