alma-memory 0.2.0__py3-none-any.whl → 0.3.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 CHANGED
@@ -14,7 +14,7 @@ This makes any tool-using agent appear to "learn" by injecting relevant
14
14
  memory slices before each run and updating memory after.
15
15
  """
16
16
 
17
- __version__ = "0.2.0"
17
+ __version__ = "0.3.0"
18
18
 
19
19
  # Core
20
20
  from alma.core import ALMA
@@ -47,6 +47,35 @@ from alma.harness.domains import (
47
47
  create_harness,
48
48
  )
49
49
 
50
+ # Progress Tracking (Phase 10)
51
+ from alma.progress import (
52
+ WorkItem,
53
+ WorkItemStatus,
54
+ ProgressLog,
55
+ ProgressSummary,
56
+ ProgressTracker,
57
+ )
58
+
59
+ # Session Management (Phase 10)
60
+ from alma.session import (
61
+ SessionHandoff,
62
+ SessionContext,
63
+ SessionOutcome,
64
+ SessionManager,
65
+ )
66
+
67
+ # Domain Memory Factory (Phase 10)
68
+ from alma.domains import (
69
+ DomainSchema,
70
+ EntityType,
71
+ RelationshipType,
72
+ DomainMemoryFactory,
73
+ get_coding_schema,
74
+ get_research_schema,
75
+ get_sales_schema,
76
+ get_general_schema,
77
+ )
78
+
50
79
  __all__ = [
51
80
  # Core
52
81
  "ALMA",
@@ -72,4 +101,24 @@ __all__ = [
72
101
  "ContentDomain",
73
102
  "OperationsDomain",
74
103
  "create_harness",
104
+ # Progress Tracking
105
+ "WorkItem",
106
+ "WorkItemStatus",
107
+ "ProgressLog",
108
+ "ProgressSummary",
109
+ "ProgressTracker",
110
+ # Session Management
111
+ "SessionHandoff",
112
+ "SessionContext",
113
+ "SessionOutcome",
114
+ "SessionManager",
115
+ # Domain Memory Factory
116
+ "DomainSchema",
117
+ "EntityType",
118
+ "RelationshipType",
119
+ "DomainMemoryFactory",
120
+ "get_coding_schema",
121
+ "get_research_schema",
122
+ "get_sales_schema",
123
+ "get_general_schema",
75
124
  ]
@@ -0,0 +1,30 @@
1
+ """
2
+ ALMA Domain Memory Module.
3
+
4
+ Provides domain-agnostic memory schemas and factory pattern
5
+ for creating domain-specific ALMA instances.
6
+ """
7
+
8
+ from alma.domains.types import (
9
+ DomainSchema,
10
+ EntityType,
11
+ RelationshipType,
12
+ )
13
+ from alma.domains.factory import DomainMemoryFactory
14
+ from alma.domains.schemas import (
15
+ get_coding_schema,
16
+ get_research_schema,
17
+ get_sales_schema,
18
+ get_general_schema,
19
+ )
20
+
21
+ __all__ = [
22
+ "DomainSchema",
23
+ "EntityType",
24
+ "RelationshipType",
25
+ "DomainMemoryFactory",
26
+ "get_coding_schema",
27
+ "get_research_schema",
28
+ "get_sales_schema",
29
+ "get_general_schema",
30
+ ]
@@ -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
+ )