forked from BasedHardware/omi
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbelief_model.py
More file actions
318 lines (269 loc) · 10.7 KB
/
Copy pathbelief_model.py
File metadata and controls
318 lines (269 loc) · 10.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
"""Read-side memory belief: currency, band, and half-life priors.
Pure functions. No I/O. Currency is never stored; no job writes it.
"""
from __future__ import annotations
import os
from dataclasses import dataclass
from datetime import datetime, timezone
from enum import Enum
from typing import Mapping, Optional
from utils.memory.decision_path_telemetry import classify_model_about
MEMORY_BELIEF_MODEL_ENABLED_ENV = "MEMORY_BELIEF_MODEL_ENABLED"
# Named classes the extractor uses. Priors are days; None means no decay.
HALF_LIFE_DAYS_BY_CLASS: Mapping[str, Optional[float]] = {
"identity": None,
"relationship": None,
"preference": 180.0,
"state": 30.0,
"plan": 30.0,
"episodic": 7.0,
"meta_residue": 1.0,
"meta_standing": None,
}
CURRENT_BAND_MIN = 0.5
FADING_BAND_MIN = 0.25
class CurrencyBand(str, Enum):
current = "current"
fading = "fading"
history = "history"
@dataclass(frozen=True)
class BeliefView:
currency: float
band: CurrencyBand
as_of: datetime
half_life_days: Optional[float]
last_evidenced_at: datetime
def belief_model_enabled() -> bool:
"""Deployment-wide flag. Unset and any value other than true fail closed to off."""
return os.getenv(MEMORY_BELIEF_MODEL_ENABLED_ENV, "false").lower() == "true"
def _coerce_aware_utc(value: datetime) -> datetime:
if value.tzinfo is None or value.utcoffset() is None:
raise ValueError("belief timestamps must be timezone-aware")
return value.astimezone(timezone.utc)
def resolve_last_evidenced_at(
*,
captured_at: datetime,
last_corroborated_at: Optional[datetime] = None,
stored_last_evidenced_at: Optional[datetime] = None,
) -> datetime:
"""Stored evidence clock. Defaults to captured_at when never re-evidenced."""
if stored_last_evidenced_at is not None:
return _coerce_aware_utc(stored_last_evidenced_at)
if last_corroborated_at is not None:
return _coerce_aware_utc(last_corroborated_at)
return _coerce_aware_utc(captured_at)
def derive_half_life_days(
*,
stored_half_life_days: Optional[float] = None,
user_asserted: bool = False,
belief_class: Optional[str] = None,
kind: Optional[str] = None,
category: Optional[str] = None,
tier: Optional[str] = None,
) -> Optional[float]:
"""Numeric stored half-life wins. ``belief_class`` supplies the class prior
(including null = no decay). Legacy rows have neither: short_term uses the
state prior, long_term/archive stay durable until backfill classifies them.
"""
if stored_half_life_days is not None:
if stored_half_life_days <= 0:
raise ValueError("half_life_days must be positive when set")
return stored_half_life_days
if user_asserted:
return None
if belief_class:
if belief_class not in HALF_LIFE_DAYS_BY_CLASS:
raise ValueError(f"unknown belief_class: {belief_class}")
return HALF_LIFE_DAYS_BY_CLASS[belief_class]
if kind in {"document", "trigger"}:
return None
# category is not a class; keep the argument so existing callers stay valid.
_ = category
if tier == "short_term":
return HALF_LIFE_DAYS_BY_CLASS["state"]
return None
USER_SUBJECT_SCOPES = frozenset({"primary_user"})
KNOWN_SUBJECT_SCOPES = frozenset(
{
"primary_user",
"user_owned_project",
"user_relationship",
"third_party",
}
)
# Extractor/backfill labels that are not released enum members. The released
# app-client contract pins MemorySubjectScope, so media and on-screen content
# is stored as third_party: non-user is what the surface bars need.
SUBJECT_SCOPE_ALIASES: Mapping[str, str] = {"media_screen": "third_party"}
def subject_scope_from_extraction(
*,
extracted_scope: Optional[str] = None,
attribution: Optional[str] = None,
about: Optional[str] = None,
user_name: Optional[str] = None,
speaker_label: Optional[str] = None,
) -> str:
"""Classify conversation-extracted subjects. Extractor-only labels are normalized via SUBJECT_SCOPE_ALIASES."""
scope = (extracted_scope or "").strip().lower()
scope = SUBJECT_SCOPE_ALIASES.get(scope, scope)
if scope in KNOWN_SUBJECT_SCOPES:
return scope
if classify_model_about(about, user_name=user_name, speaker_label=speaker_label) == "primary_user":
return "primary_user"
if attribution == "user":
return "primary_user"
if attribution == "third_party":
return "third_party"
return "third_party"
def horizon_from_extraction(
*,
belief_class: Optional[str],
half_life_days_override: Optional[float] = None,
user_asserted: bool = False,
) -> tuple[Optional[str], Optional[float]]:
"""Return (belief_class, half_life_days) for a new claim."""
if user_asserted:
return (belief_class or "identity", None)
resolved_class = belief_class if belief_class is not None and belief_class in HALF_LIFE_DAYS_BY_CLASS else "state"
if half_life_days_override is not None:
if half_life_days_override <= 0:
raise ValueError("half_life_days must be positive when set")
return resolved_class, half_life_days_override
return resolved_class, HALF_LIFE_DAYS_BY_CLASS[resolved_class]
def compute_currency(
*,
half_life_days: Optional[float],
last_evidenced_at: datetime,
now: datetime,
valid_to: Optional[datetime] = None,
) -> float:
"""Read-side currency. Named-date claims use valid_to instead of a half-life."""
current_time = _coerce_aware_utc(now)
evidenced = _coerce_aware_utc(last_evidenced_at)
if valid_to is not None:
return 1.0 if current_time <= _coerce_aware_utc(valid_to) else 0.0
if half_life_days is None:
return 1.0
if half_life_days <= 0:
raise ValueError("half_life_days must be positive when set")
days_since = max(0.0, (current_time - evidenced).total_seconds() / 86400.0)
return 0.5 ** (days_since / half_life_days)
def currency_band(currency: float) -> CurrencyBand:
if currency > CURRENT_BAND_MIN:
return CurrencyBand.current
if currency >= FADING_BAND_MIN:
return CurrencyBand.fading
return CurrencyBand.history
def belief_view(
*,
captured_at: datetime,
now: datetime,
stored_half_life_days: Optional[float] = None,
last_corroborated_at: Optional[datetime] = None,
stored_last_evidenced_at: Optional[datetime] = None,
valid_to: Optional[datetime] = None,
user_asserted: bool = False,
belief_class: Optional[str] = None,
kind: Optional[str] = None,
category: Optional[str] = None,
tier: Optional[str] = None,
) -> BeliefView:
evidenced = resolve_last_evidenced_at(
captured_at=captured_at,
last_corroborated_at=last_corroborated_at,
stored_last_evidenced_at=stored_last_evidenced_at,
)
half_life = derive_half_life_days(
stored_half_life_days=stored_half_life_days,
user_asserted=user_asserted,
belief_class=belief_class,
kind=kind,
category=category,
tier=tier,
)
value = compute_currency(
half_life_days=half_life,
last_evidenced_at=evidenced,
now=now,
valid_to=valid_to,
)
return BeliefView(
currency=value,
band=currency_band(value),
as_of=evidenced,
half_life_days=half_life,
last_evidenced_at=evidenced,
)
def is_user_subject(subject_scope: Optional[str]) -> bool:
return subject_scope in USER_SUBJECT_SCOPES
def is_contradicted(*, superseded_by: Optional[str] = None, confidence: Optional[float] = None) -> bool:
if superseded_by:
return True
return confidence is not None and confidence <= 0.0
def passes_proactive_bar(
view: BeliefView,
*,
subject_scope: Optional[str],
superseded_by: Optional[str] = None,
confidence: Optional[float] = None,
) -> bool:
"""JIT / proactive nudges: current band, user subject, truth not contradicted."""
return (
view.band == CurrencyBand.current
and is_user_subject(subject_scope)
and not is_contradicted(superseded_by=superseded_by, confidence=confidence)
)
def _enum_value(value: object) -> Optional[str]:
if value is None:
return None
raw = getattr(value, "value", value)
return raw if isinstance(raw, str) else None
def _record_category(item: object) -> Optional[str]:
"""Category from MemoryDB.category or the item audit bag."""
direct = _enum_value(getattr(item, "category", None))
if direct:
return direct
audit = getattr(item, "".join(("pro", "motion")), None) or {}
value = audit.get("category") if isinstance(audit, Mapping) else None
return value if isinstance(value, str) else None
def belief_view_for_record(item: object, *, now: datetime) -> BeliefView:
"""Read-side view from a MemoryItem or MemoryDB-shaped record. No I/O."""
captured_at = getattr(item, "captured_at", None) or getattr(item, "created_at")
return belief_view(
captured_at=captured_at,
now=now,
stored_half_life_days=getattr(item, "half_life_days", None),
last_corroborated_at=getattr(item, "last_corroborated_at", None),
valid_to=getattr(item, "valid_to", None) or getattr(item, "invalid_at", None),
user_asserted=bool(getattr(item, "user_asserted", False) or getattr(item, "manually_added", False)),
belief_class=getattr(item, "belief_class", None),
kind=_enum_value(getattr(item, "kind", None)),
category=_record_category(item),
tier=_enum_value(getattr(item, "tier", None)) or _enum_value(getattr(item, "memory_tier", None)),
)
def record_passes_proactive_bar(item: object, *, now: datetime) -> bool:
scope = getattr(item, "subject_scope", None)
return passes_proactive_bar(
belief_view_for_record(item, now=now),
subject_scope=_enum_value(scope) or (scope if isinstance(scope, str) else None),
superseded_by=getattr(item, "superseded_by", None),
confidence=getattr(item, "confidence", None),
)
def public_belief_overlay(item: object, *, now: datetime) -> dict[str, object]:
"""Additive read fields. Empty when the flag is off so payloads stay identical."""
if not belief_model_enabled():
return {}
view = belief_view_for_record(item, now=now)
return {
"currency": view.currency,
"currency_band": view.band.value,
"as_of": view.as_of,
"half_life_days": view.half_life_days,
"belief_class": getattr(item, "belief_class", None),
}
def public_belief_overlay_json(item: object, *, now: datetime) -> dict[str, object]:
overlay = public_belief_overlay(item, now=now)
as_of = overlay.get("as_of")
if isinstance(as_of, datetime):
overlay = {**overlay, "as_of": as_of.isoformat()}
return overlay