hb-cortex-memory 0.1.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.
- cortex_memory/__init__.py +126 -0
- cortex_memory/_textutil.py +83 -0
- cortex_memory/assembly.py +335 -0
- cortex_memory/db.py +25 -0
- cortex_memory/domains.py +158 -0
- cortex_memory/dreaming.py +568 -0
- cortex_memory/dreaming_prompts.py +55 -0
- cortex_memory/dtos.py +260 -0
- cortex_memory/embedding.py +58 -0
- cortex_memory/enums.py +78 -0
- cortex_memory/episodic_tree.py +466 -0
- cortex_memory/experience_tree.py +230 -0
- cortex_memory/graph.py +409 -0
- cortex_memory/ingestion.py +224 -0
- cortex_memory/intelligence_tree.py +275 -0
- cortex_memory/knowledge_tree.py +483 -0
- cortex_memory/models.py +240 -0
- cortex_memory/prompts.py +21 -0
- cortex_memory/providers.py +156 -0
- cortex_memory/providers_reference.py +121 -0
- cortex_memory/py.typed +0 -0
- cortex_memory/schema.py +43 -0
- cortex_memory/scope_policy.py +53 -0
- cortex_memory/service.py +1196 -0
- hb_cortex_memory-0.1.0.dist-info/METADATA +168 -0
- hb_cortex_memory-0.1.0.dist-info/RECORD +29 -0
- hb_cortex_memory-0.1.0.dist-info/WHEEL +5 -0
- hb_cortex_memory-0.1.0.dist-info/licenses/LICENSE +201 -0
- hb_cortex_memory-0.1.0.dist-info/top_level.txt +1 -0
cortex_memory/domains.py
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"""
|
|
2
|
+
cortex_memory.domains — DomainTreeBase + retrieval-weight registry.
|
|
3
|
+
|
|
4
|
+
Each memory domain (Knowledge / Episodic / Experience / Intelligence) is a typed
|
|
5
|
+
view over the CORTEX substrate. This module captures three things:
|
|
6
|
+
|
|
7
|
+
1. The *signal vector* every domain ranks against: ``semantic``, ``recency``,
|
|
8
|
+
``user_match``, ``success``.
|
|
9
|
+
2. The per-domain **retrieval weights** (constants below).
|
|
10
|
+
3. A pure ``score_signals`` helper that turns a signal dict into a single
|
|
11
|
+
weighted score.
|
|
12
|
+
|
|
13
|
+
A self-contained tree primitive (no host dependency); moved out of the host
|
|
14
|
+
(Phase 12 `04`). The host re-exports it from ``ai.memory.domains``.
|
|
15
|
+
"""
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import logging
|
|
19
|
+
from abc import ABC
|
|
20
|
+
from dataclasses import dataclass, field
|
|
21
|
+
from typing import Any, ClassVar, Optional
|
|
22
|
+
from uuid import UUID
|
|
23
|
+
|
|
24
|
+
logger = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
_REQUIRED_SIGNALS = ("semantic", "recency", "user_match", "success")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# ---------------------------------------------------------------------------
|
|
31
|
+
# Canonical per-domain weights.
|
|
32
|
+
# ---------------------------------------------------------------------------
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
KnowledgeWeights: dict[str, float] = {
|
|
36
|
+
"semantic": 1.0, "recency": 0.4, "user_match": 0.0, "success": 0.0,
|
|
37
|
+
}
|
|
38
|
+
ExperienceWeights: dict[str, float] = {
|
|
39
|
+
"semantic": 0.7, "recency": 0.5, "user_match": 0.2, "success": 0.6,
|
|
40
|
+
}
|
|
41
|
+
IntelligenceWeights: dict[str, float] = {
|
|
42
|
+
"semantic": 0.6, "recency": 0.3, "user_match": 0.0, "success": 0.0,
|
|
43
|
+
}
|
|
44
|
+
EpisodicWeights: dict[str, float] = {
|
|
45
|
+
"semantic": 0.5, "recency": 0.7, "user_match": 0.6, "success": 0.5,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
DEFAULT_DOMAIN_WEIGHTS: dict[str, dict[str, float]] = {
|
|
49
|
+
"knowledge": KnowledgeWeights,
|
|
50
|
+
"experience": ExperienceWeights,
|
|
51
|
+
"intelligence": IntelligenceWeights,
|
|
52
|
+
"episodic": EpisodicWeights,
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# ---------------------------------------------------------------------------
|
|
57
|
+
# Pure scoring helper
|
|
58
|
+
# ---------------------------------------------------------------------------
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def score_signals(
|
|
62
|
+
weights: dict[str, float],
|
|
63
|
+
signals: dict[str, float],
|
|
64
|
+
) -> float:
|
|
65
|
+
"""Weighted average over the canonical signal vector.
|
|
66
|
+
|
|
67
|
+
Missing signals are treated as 0; the denominator uses the declared weights
|
|
68
|
+
(not the present signals) so domains that always want recency see
|
|
69
|
+
partial-credit penalties when recency is missing. Returns 0.0 when the
|
|
70
|
+
weight vector is all zero (defensive).
|
|
71
|
+
"""
|
|
72
|
+
total_weight = sum(max(0.0, w) for w in weights.values())
|
|
73
|
+
if total_weight <= 0:
|
|
74
|
+
return 0.0
|
|
75
|
+
accum = 0.0
|
|
76
|
+
for key in _REQUIRED_SIGNALS:
|
|
77
|
+
w = max(0.0, float(weights.get(key, 0.0)))
|
|
78
|
+
s = max(0.0, float(signals.get(key, 0.0)))
|
|
79
|
+
accum += w * s
|
|
80
|
+
return accum / total_weight
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# ---------------------------------------------------------------------------
|
|
84
|
+
# Typed retrieval result
|
|
85
|
+
# ---------------------------------------------------------------------------
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@dataclass
|
|
89
|
+
class DomainItem:
|
|
90
|
+
"""One retrievable item from a domain tree (post-scoring)."""
|
|
91
|
+
|
|
92
|
+
node_id: UUID
|
|
93
|
+
title: str
|
|
94
|
+
summary: Optional[str]
|
|
95
|
+
domain: str
|
|
96
|
+
score: float = 0.0
|
|
97
|
+
signals: dict[str, float] = field(default_factory=dict)
|
|
98
|
+
payload: dict[str, Any] = field(default_factory=dict)
|
|
99
|
+
|
|
100
|
+
def to_dict(self) -> dict[str, Any]:
|
|
101
|
+
return {
|
|
102
|
+
"node_id": str(self.node_id),
|
|
103
|
+
"title": self.title,
|
|
104
|
+
"summary": self.summary,
|
|
105
|
+
"domain": self.domain,
|
|
106
|
+
"score": self.score,
|
|
107
|
+
"signals": dict(self.signals),
|
|
108
|
+
"payload": dict(self.payload),
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
# ---------------------------------------------------------------------------
|
|
113
|
+
# Base class
|
|
114
|
+
# ---------------------------------------------------------------------------
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class DomainTreeBase(ABC):
|
|
118
|
+
"""Optional base for domain tree services. New domain code SHOULD subclass
|
|
119
|
+
to inherit the retrieval-weight contract and the pure scorer."""
|
|
120
|
+
|
|
121
|
+
DOMAIN: ClassVar[str] = "general"
|
|
122
|
+
ROOT_TITLE: ClassVar[str] = "Tree"
|
|
123
|
+
SECTIONS: ClassVar[dict[str, str]] = {}
|
|
124
|
+
RETRIEVAL_WEIGHTS: ClassVar[dict[str, float]] = KnowledgeWeights
|
|
125
|
+
|
|
126
|
+
def __init__(self, db: Any, company_id: UUID):
|
|
127
|
+
self.db = db
|
|
128
|
+
self.company_id = company_id
|
|
129
|
+
|
|
130
|
+
async def ensure_tree(self, *, scope_id: UUID, scope_level: str) -> Any: # pragma: no cover
|
|
131
|
+
raise NotImplementedError
|
|
132
|
+
|
|
133
|
+
async def ensure_section(self, tree: Any, section_type: str) -> Any: # pragma: no cover
|
|
134
|
+
raise NotImplementedError
|
|
135
|
+
|
|
136
|
+
async def write_item(self, **kwargs: Any) -> Any: # pragma: no cover
|
|
137
|
+
raise NotImplementedError
|
|
138
|
+
|
|
139
|
+
async def find(
|
|
140
|
+
self, *, tree: Any, query: str, top_k: int = 5,
|
|
141
|
+
filters: Optional[dict[str, Any]] = None,
|
|
142
|
+
) -> list[DomainItem]: # pragma: no cover
|
|
143
|
+
raise NotImplementedError
|
|
144
|
+
|
|
145
|
+
def score(self, signals: dict[str, float]) -> float:
|
|
146
|
+
return score_signals(self.RETRIEVAL_WEIGHTS, signals)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
__all__ = [
|
|
150
|
+
"DomainItem",
|
|
151
|
+
"DomainTreeBase",
|
|
152
|
+
"DEFAULT_DOMAIN_WEIGHTS",
|
|
153
|
+
"KnowledgeWeights",
|
|
154
|
+
"EpisodicWeights",
|
|
155
|
+
"ExperienceWeights",
|
|
156
|
+
"IntelligenceWeights",
|
|
157
|
+
"score_signals",
|
|
158
|
+
]
|