alma-memory 0.4.0__py3-none-any.whl → 0.5.1__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 +121 -45
- 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 +136 -28
- 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 +265 -0
- alma/extraction/extractor.py +420 -0
- alma/graph/__init__.py +106 -0
- alma/graph/backends/__init__.py +32 -0
- alma/graph/backends/kuzu.py +624 -0
- alma/graph/backends/memgraph.py +432 -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 +32 -20
- 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 +65 -17
- 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 +180 -45
- alma/observability/__init__.py +84 -0
- alma/observability/config.py +302 -0
- alma/observability/logging.py +424 -0
- alma/observability/metrics.py +583 -0
- alma/observability/tracing.py +440 -0
- 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 +179 -39
- 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 +70 -0
- alma/storage/azure_cosmos.py +414 -133
- alma/storage/base.py +215 -4
- alma/storage/chroma.py +1443 -0
- alma/storage/constants.py +103 -0
- alma/storage/file_based.py +59 -28
- alma/storage/migrations/__init__.py +21 -0
- alma/storage/migrations/base.py +321 -0
- alma/storage/migrations/runner.py +323 -0
- alma/storage/migrations/version_stores.py +337 -0
- alma/storage/migrations/versions/__init__.py +11 -0
- alma/storage/migrations/versions/v1_0_0.py +373 -0
- alma/storage/pinecone.py +1080 -0
- alma/storage/postgresql.py +1559 -0
- alma/storage/qdrant.py +1306 -0
- alma/storage/sqlite_local.py +504 -60
- alma/testing/__init__.py +46 -0
- alma/testing/factories.py +301 -0
- alma/testing/mocks.py +389 -0
- alma/types.py +62 -14
- alma_memory-0.5.1.dist-info/METADATA +939 -0
- alma_memory-0.5.1.dist-info/RECORD +93 -0
- {alma_memory-0.4.0.dist-info → alma_memory-0.5.1.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.1.dist-info}/top_level.txt +0 -0
alma/storage/base.py
CHANGED
|
@@ -5,16 +5,15 @@ Abstract base class that all storage backends must implement.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
from abc import ABC, abstractmethod
|
|
8
|
-
from typing import Optional, List, Dict, Any
|
|
9
8
|
from datetime import datetime
|
|
9
|
+
from typing import Any, Dict, List, Optional
|
|
10
10
|
|
|
11
11
|
from alma.types import (
|
|
12
|
+
AntiPattern,
|
|
13
|
+
DomainKnowledge,
|
|
12
14
|
Heuristic,
|
|
13
15
|
Outcome,
|
|
14
16
|
UserPreference,
|
|
15
|
-
DomainKnowledge,
|
|
16
|
-
AntiPattern,
|
|
17
|
-
MemoryType,
|
|
18
17
|
)
|
|
19
18
|
|
|
20
19
|
|
|
@@ -55,6 +54,22 @@ class StorageBackend(ABC):
|
|
|
55
54
|
"""Save an anti-pattern, return its ID."""
|
|
56
55
|
pass
|
|
57
56
|
|
|
57
|
+
# ==================== BATCH WRITE OPERATIONS ====================
|
|
58
|
+
|
|
59
|
+
def save_heuristics(self, heuristics: List[Heuristic]) -> List[str]:
|
|
60
|
+
"""Save multiple heuristics in a batch. Default implementation calls save_heuristic in a loop."""
|
|
61
|
+
return [self.save_heuristic(h) for h in heuristics]
|
|
62
|
+
|
|
63
|
+
def save_outcomes(self, outcomes: List[Outcome]) -> List[str]:
|
|
64
|
+
"""Save multiple outcomes in a batch. Default implementation calls save_outcome in a loop."""
|
|
65
|
+
return [self.save_outcome(o) for o in outcomes]
|
|
66
|
+
|
|
67
|
+
def save_domain_knowledge_batch(
|
|
68
|
+
self, knowledge_items: List[DomainKnowledge]
|
|
69
|
+
) -> List[str]:
|
|
70
|
+
"""Save multiple domain knowledge items in a batch. Default implementation calls save_domain_knowledge in a loop."""
|
|
71
|
+
return [self.save_domain_knowledge(k) for k in knowledge_items]
|
|
72
|
+
|
|
58
73
|
# ==================== READ OPERATIONS ====================
|
|
59
74
|
|
|
60
75
|
@abstractmethod
|
|
@@ -339,6 +354,144 @@ class StorageBackend(ABC):
|
|
|
339
354
|
"""
|
|
340
355
|
pass
|
|
341
356
|
|
|
357
|
+
# ==================== MULTI-AGENT MEMORY SHARING ====================
|
|
358
|
+
|
|
359
|
+
def get_heuristics_for_agents(
|
|
360
|
+
self,
|
|
361
|
+
project_id: str,
|
|
362
|
+
agents: List[str],
|
|
363
|
+
embedding: Optional[List[float]] = None,
|
|
364
|
+
top_k: int = 5,
|
|
365
|
+
min_confidence: float = 0.0,
|
|
366
|
+
) -> List[Heuristic]:
|
|
367
|
+
"""
|
|
368
|
+
Get heuristics from multiple agents in one call.
|
|
369
|
+
|
|
370
|
+
This enables multi-agent memory sharing where an agent can
|
|
371
|
+
read memories from agents it inherits from.
|
|
372
|
+
|
|
373
|
+
Args:
|
|
374
|
+
project_id: Project to query
|
|
375
|
+
agents: List of agent names to query
|
|
376
|
+
embedding: Query embedding for semantic search
|
|
377
|
+
top_k: Max results to return per agent
|
|
378
|
+
min_confidence: Minimum confidence threshold
|
|
379
|
+
|
|
380
|
+
Returns:
|
|
381
|
+
List of matching heuristics from all specified agents
|
|
382
|
+
"""
|
|
383
|
+
# Default implementation: query each agent individually
|
|
384
|
+
results = []
|
|
385
|
+
for agent in agents:
|
|
386
|
+
agent_heuristics = self.get_heuristics(
|
|
387
|
+
project_id=project_id,
|
|
388
|
+
agent=agent,
|
|
389
|
+
embedding=embedding,
|
|
390
|
+
top_k=top_k,
|
|
391
|
+
min_confidence=min_confidence,
|
|
392
|
+
)
|
|
393
|
+
results.extend(agent_heuristics)
|
|
394
|
+
return results
|
|
395
|
+
|
|
396
|
+
def get_outcomes_for_agents(
|
|
397
|
+
self,
|
|
398
|
+
project_id: str,
|
|
399
|
+
agents: List[str],
|
|
400
|
+
task_type: Optional[str] = None,
|
|
401
|
+
embedding: Optional[List[float]] = None,
|
|
402
|
+
top_k: int = 5,
|
|
403
|
+
success_only: bool = False,
|
|
404
|
+
) -> List[Outcome]:
|
|
405
|
+
"""
|
|
406
|
+
Get outcomes from multiple agents in one call.
|
|
407
|
+
|
|
408
|
+
Args:
|
|
409
|
+
project_id: Project to query
|
|
410
|
+
agents: List of agent names to query
|
|
411
|
+
task_type: Filter by task type
|
|
412
|
+
embedding: Query embedding for semantic search
|
|
413
|
+
top_k: Max results to return per agent
|
|
414
|
+
success_only: Only return successful outcomes
|
|
415
|
+
|
|
416
|
+
Returns:
|
|
417
|
+
List of matching outcomes from all specified agents
|
|
418
|
+
"""
|
|
419
|
+
results = []
|
|
420
|
+
for agent in agents:
|
|
421
|
+
agent_outcomes = self.get_outcomes(
|
|
422
|
+
project_id=project_id,
|
|
423
|
+
agent=agent,
|
|
424
|
+
task_type=task_type,
|
|
425
|
+
embedding=embedding,
|
|
426
|
+
top_k=top_k,
|
|
427
|
+
success_only=success_only,
|
|
428
|
+
)
|
|
429
|
+
results.extend(agent_outcomes)
|
|
430
|
+
return results
|
|
431
|
+
|
|
432
|
+
def get_domain_knowledge_for_agents(
|
|
433
|
+
self,
|
|
434
|
+
project_id: str,
|
|
435
|
+
agents: List[str],
|
|
436
|
+
domain: Optional[str] = None,
|
|
437
|
+
embedding: Optional[List[float]] = None,
|
|
438
|
+
top_k: int = 5,
|
|
439
|
+
) -> List[DomainKnowledge]:
|
|
440
|
+
"""
|
|
441
|
+
Get domain knowledge from multiple agents in one call.
|
|
442
|
+
|
|
443
|
+
Args:
|
|
444
|
+
project_id: Project to query
|
|
445
|
+
agents: List of agent names to query
|
|
446
|
+
domain: Filter by domain
|
|
447
|
+
embedding: Query embedding for semantic search
|
|
448
|
+
top_k: Max results to return per agent
|
|
449
|
+
|
|
450
|
+
Returns:
|
|
451
|
+
List of matching domain knowledge from all specified agents
|
|
452
|
+
"""
|
|
453
|
+
results = []
|
|
454
|
+
for agent in agents:
|
|
455
|
+
agent_knowledge = self.get_domain_knowledge(
|
|
456
|
+
project_id=project_id,
|
|
457
|
+
agent=agent,
|
|
458
|
+
domain=domain,
|
|
459
|
+
embedding=embedding,
|
|
460
|
+
top_k=top_k,
|
|
461
|
+
)
|
|
462
|
+
results.extend(agent_knowledge)
|
|
463
|
+
return results
|
|
464
|
+
|
|
465
|
+
def get_anti_patterns_for_agents(
|
|
466
|
+
self,
|
|
467
|
+
project_id: str,
|
|
468
|
+
agents: List[str],
|
|
469
|
+
embedding: Optional[List[float]] = None,
|
|
470
|
+
top_k: int = 5,
|
|
471
|
+
) -> List[AntiPattern]:
|
|
472
|
+
"""
|
|
473
|
+
Get anti-patterns from multiple agents in one call.
|
|
474
|
+
|
|
475
|
+
Args:
|
|
476
|
+
project_id: Project to query
|
|
477
|
+
agents: List of agent names to query
|
|
478
|
+
embedding: Query embedding for semantic search
|
|
479
|
+
top_k: Max results to return per agent
|
|
480
|
+
|
|
481
|
+
Returns:
|
|
482
|
+
List of matching anti-patterns from all specified agents
|
|
483
|
+
"""
|
|
484
|
+
results = []
|
|
485
|
+
for agent in agents:
|
|
486
|
+
agent_patterns = self.get_anti_patterns(
|
|
487
|
+
project_id=project_id,
|
|
488
|
+
agent=agent,
|
|
489
|
+
embedding=embedding,
|
|
490
|
+
top_k=top_k,
|
|
491
|
+
)
|
|
492
|
+
results.extend(agent_patterns)
|
|
493
|
+
return results
|
|
494
|
+
|
|
342
495
|
# ==================== STATS ====================
|
|
343
496
|
|
|
344
497
|
@abstractmethod
|
|
@@ -355,6 +508,64 @@ class StorageBackend(ABC):
|
|
|
355
508
|
"""
|
|
356
509
|
pass
|
|
357
510
|
|
|
511
|
+
# ==================== MIGRATION SUPPORT ====================
|
|
512
|
+
|
|
513
|
+
def get_schema_version(self) -> Optional[str]:
|
|
514
|
+
"""
|
|
515
|
+
Get the current schema version.
|
|
516
|
+
|
|
517
|
+
Returns:
|
|
518
|
+
Current schema version string, or None if not tracked
|
|
519
|
+
"""
|
|
520
|
+
# Default implementation returns None (no version tracking)
|
|
521
|
+
return None
|
|
522
|
+
|
|
523
|
+
def get_migration_status(self) -> Dict[str, Any]:
|
|
524
|
+
"""
|
|
525
|
+
Get migration status information.
|
|
526
|
+
|
|
527
|
+
Returns:
|
|
528
|
+
Dict with current version, pending migrations, etc.
|
|
529
|
+
"""
|
|
530
|
+
return {
|
|
531
|
+
"current_version": self.get_schema_version(),
|
|
532
|
+
"target_version": None,
|
|
533
|
+
"pending_count": 0,
|
|
534
|
+
"pending_versions": [],
|
|
535
|
+
"needs_migration": False,
|
|
536
|
+
"migration_supported": False,
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
def migrate(
|
|
540
|
+
self, target_version: Optional[str] = None, dry_run: bool = False
|
|
541
|
+
) -> List[str]:
|
|
542
|
+
"""
|
|
543
|
+
Apply pending schema migrations.
|
|
544
|
+
|
|
545
|
+
Args:
|
|
546
|
+
target_version: Optional target version (applies all if not specified)
|
|
547
|
+
dry_run: If True, show what would be done without making changes
|
|
548
|
+
|
|
549
|
+
Returns:
|
|
550
|
+
List of applied migration versions
|
|
551
|
+
"""
|
|
552
|
+
# Default implementation does nothing
|
|
553
|
+
return []
|
|
554
|
+
|
|
555
|
+
def rollback(self, target_version: str, dry_run: bool = False) -> List[str]:
|
|
556
|
+
"""
|
|
557
|
+
Roll back schema to a previous version.
|
|
558
|
+
|
|
559
|
+
Args:
|
|
560
|
+
target_version: Version to roll back to
|
|
561
|
+
dry_run: If True, show what would be done without making changes
|
|
562
|
+
|
|
563
|
+
Returns:
|
|
564
|
+
List of rolled back migration versions
|
|
565
|
+
"""
|
|
566
|
+
# Default implementation does nothing
|
|
567
|
+
return []
|
|
568
|
+
|
|
358
569
|
# ==================== UTILITY ====================
|
|
359
570
|
|
|
360
571
|
@classmethod
|