alma-memory 0.5.0__py3-none-any.whl → 0.7.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 +296 -194
- alma/compression/__init__.py +33 -0
- alma/compression/pipeline.py +980 -0
- alma/confidence/__init__.py +47 -47
- alma/confidence/engine.py +540 -540
- alma/confidence/types.py +351 -351
- alma/config/loader.py +157 -157
- alma/consolidation/__init__.py +23 -23
- alma/consolidation/engine.py +678 -678
- alma/consolidation/prompts.py +84 -84
- alma/core.py +1189 -322
- alma/domains/__init__.py +30 -30
- alma/domains/factory.py +359 -359
- alma/domains/schemas.py +448 -448
- alma/domains/types.py +272 -272
- alma/events/__init__.py +75 -75
- alma/events/emitter.py +285 -284
- alma/events/storage_mixin.py +246 -246
- alma/events/types.py +126 -126
- alma/events/webhook.py +425 -425
- alma/exceptions.py +49 -49
- alma/extraction/__init__.py +31 -31
- alma/extraction/auto_learner.py +265 -264
- alma/extraction/extractor.py +420 -420
- alma/graph/__init__.py +106 -81
- alma/graph/backends/__init__.py +32 -18
- alma/graph/backends/kuzu.py +624 -0
- alma/graph/backends/memgraph.py +432 -0
- alma/graph/backends/memory.py +236 -236
- alma/graph/backends/neo4j.py +417 -417
- alma/graph/base.py +159 -159
- alma/graph/extraction.py +198 -198
- alma/graph/store.py +860 -860
- alma/harness/__init__.py +35 -35
- alma/harness/base.py +386 -386
- alma/harness/domains.py +705 -705
- alma/initializer/__init__.py +37 -37
- alma/initializer/initializer.py +418 -418
- alma/initializer/types.py +250 -250
- alma/integration/__init__.py +62 -62
- alma/integration/claude_agents.py +444 -432
- alma/integration/helena.py +423 -423
- alma/integration/victor.py +471 -471
- alma/learning/__init__.py +101 -86
- alma/learning/decay.py +878 -0
- alma/learning/forgetting.py +1446 -1446
- alma/learning/heuristic_extractor.py +390 -390
- alma/learning/protocols.py +374 -374
- alma/learning/validation.py +346 -346
- alma/mcp/__init__.py +123 -45
- alma/mcp/__main__.py +156 -156
- alma/mcp/resources.py +122 -122
- alma/mcp/server.py +955 -591
- alma/mcp/tools.py +3254 -511
- alma/observability/__init__.py +91 -0
- alma/observability/config.py +302 -0
- alma/observability/guidelines.py +170 -0
- alma/observability/logging.py +424 -0
- alma/observability/metrics.py +583 -0
- alma/observability/tracing.py +440 -0
- alma/progress/__init__.py +21 -21
- alma/progress/tracker.py +607 -607
- alma/progress/types.py +250 -250
- alma/retrieval/__init__.py +134 -53
- alma/retrieval/budget.py +525 -0
- alma/retrieval/cache.py +1304 -1061
- alma/retrieval/embeddings.py +202 -202
- alma/retrieval/engine.py +850 -366
- alma/retrieval/modes.py +365 -0
- alma/retrieval/progressive.py +560 -0
- alma/retrieval/scoring.py +344 -344
- alma/retrieval/trust_scoring.py +637 -0
- alma/retrieval/verification.py +797 -0
- alma/session/__init__.py +19 -19
- alma/session/manager.py +442 -399
- alma/session/types.py +288 -288
- alma/storage/__init__.py +101 -61
- alma/storage/archive.py +233 -0
- alma/storage/azure_cosmos.py +1259 -1048
- alma/storage/base.py +1083 -525
- alma/storage/chroma.py +1443 -1443
- alma/storage/constants.py +103 -0
- alma/storage/file_based.py +614 -619
- 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/migrations/versions/v1_1_0_workflow_context.py +551 -0
- alma/storage/pinecone.py +1080 -1080
- alma/storage/postgresql.py +1948 -1452
- alma/storage/qdrant.py +1306 -1306
- alma/storage/sqlite_local.py +3041 -1358
- alma/testing/__init__.py +46 -0
- alma/testing/factories.py +301 -0
- alma/testing/mocks.py +389 -0
- alma/types.py +292 -264
- alma/utils/__init__.py +19 -0
- alma/utils/tokenizer.py +521 -0
- alma/workflow/__init__.py +83 -0
- alma/workflow/artifacts.py +170 -0
- alma/workflow/checkpoint.py +311 -0
- alma/workflow/context.py +228 -0
- alma/workflow/outcomes.py +189 -0
- alma/workflow/reducers.py +393 -0
- {alma_memory-0.5.0.dist-info → alma_memory-0.7.0.dist-info}/METADATA +244 -72
- alma_memory-0.7.0.dist-info/RECORD +112 -0
- alma_memory-0.5.0.dist-info/RECORD +0 -76
- {alma_memory-0.5.0.dist-info → alma_memory-0.7.0.dist-info}/WHEEL +0 -0
- {alma_memory-0.5.0.dist-info → alma_memory-0.7.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,637 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ALMA Trust-Integrated Scoring.
|
|
3
|
+
|
|
4
|
+
Extends memory scoring to incorporate trust patterns from agent behavior.
|
|
5
|
+
Based on Veritas trust evolution concepts:
|
|
6
|
+
- Trust decays without activity
|
|
7
|
+
- Per-behavior trust tracking
|
|
8
|
+
- Cross-session trust persistence
|
|
9
|
+
|
|
10
|
+
Features:
|
|
11
|
+
- Trust-weighted scoring for memories from different sources
|
|
12
|
+
- Agent trust profile integration
|
|
13
|
+
- Trust pattern storage and retrieval
|
|
14
|
+
- Violation-aware scoring (anti-patterns from violations)
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import logging
|
|
18
|
+
import math
|
|
19
|
+
from dataclasses import dataclass, field
|
|
20
|
+
from datetime import datetime, timezone
|
|
21
|
+
from typing import Any, Dict, List, Optional
|
|
22
|
+
|
|
23
|
+
from alma.retrieval.scoring import MemoryScorer, ScoredItem, ScoringWeights
|
|
24
|
+
from alma.types import (
|
|
25
|
+
AntiPattern,
|
|
26
|
+
Heuristic,
|
|
27
|
+
MemorySlice,
|
|
28
|
+
Outcome,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
logger = logging.getLogger(__name__)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class TrustLevel:
|
|
35
|
+
"""Trust level constants matching Veritas framework."""
|
|
36
|
+
|
|
37
|
+
UNTRUSTED = 0.0
|
|
38
|
+
MINIMAL = 0.2
|
|
39
|
+
LOW = 0.4
|
|
40
|
+
MODERATE = 0.5
|
|
41
|
+
GOOD = 0.7
|
|
42
|
+
HIGH = 0.85
|
|
43
|
+
FULL = 1.0
|
|
44
|
+
|
|
45
|
+
@classmethod
|
|
46
|
+
def label(cls, score: float) -> str:
|
|
47
|
+
"""Get human-readable label for trust score."""
|
|
48
|
+
if score >= cls.FULL:
|
|
49
|
+
return "FULL"
|
|
50
|
+
elif score >= cls.HIGH:
|
|
51
|
+
return "HIGH"
|
|
52
|
+
elif score >= cls.GOOD:
|
|
53
|
+
return "GOOD"
|
|
54
|
+
elif score >= cls.MODERATE:
|
|
55
|
+
return "MODERATE"
|
|
56
|
+
elif score >= cls.LOW:
|
|
57
|
+
return "LOW"
|
|
58
|
+
elif score >= cls.MINIMAL:
|
|
59
|
+
return "MINIMAL"
|
|
60
|
+
return "UNTRUSTED"
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@dataclass
|
|
64
|
+
class TrustWeights(ScoringWeights):
|
|
65
|
+
"""
|
|
66
|
+
Extended scoring weights that include trust factor.
|
|
67
|
+
|
|
68
|
+
Extends base ScoringWeights with trust component.
|
|
69
|
+
All weights are normalized to sum to 1.0.
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
# Inherited from ScoringWeights
|
|
73
|
+
similarity: float = 0.35
|
|
74
|
+
recency: float = 0.25
|
|
75
|
+
success_rate: float = 0.15
|
|
76
|
+
confidence: float = 0.10
|
|
77
|
+
|
|
78
|
+
# Trust factor
|
|
79
|
+
trust: float = 0.15 # Agent/source trust score
|
|
80
|
+
|
|
81
|
+
def __post_init__(self):
|
|
82
|
+
"""Validate and normalize weights."""
|
|
83
|
+
total = (
|
|
84
|
+
self.similarity
|
|
85
|
+
+ self.recency
|
|
86
|
+
+ self.success_rate
|
|
87
|
+
+ self.confidence
|
|
88
|
+
+ self.trust
|
|
89
|
+
)
|
|
90
|
+
if not (0.99 <= total <= 1.01):
|
|
91
|
+
# Normalize
|
|
92
|
+
self.similarity /= total
|
|
93
|
+
self.recency /= total
|
|
94
|
+
self.success_rate /= total
|
|
95
|
+
self.confidence /= total
|
|
96
|
+
self.trust /= total
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@dataclass
|
|
100
|
+
class AgentTrustProfile:
|
|
101
|
+
"""
|
|
102
|
+
Trust profile for an agent, stored in ALMA memory.
|
|
103
|
+
|
|
104
|
+
Tracks trust metrics that influence memory scoring.
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
agent_id: str
|
|
108
|
+
current_trust: float = TrustLevel.MODERATE
|
|
109
|
+
sessions_completed: int = 0
|
|
110
|
+
total_actions: int = 0
|
|
111
|
+
total_violations: int = 0
|
|
112
|
+
consecutive_clean_sessions: int = 0
|
|
113
|
+
last_session: Optional[datetime] = None
|
|
114
|
+
trust_half_life_days: int = 30
|
|
115
|
+
|
|
116
|
+
# Per-behavior trust scores
|
|
117
|
+
behavior_trust: Dict[str, float] = field(
|
|
118
|
+
default_factory=lambda: {
|
|
119
|
+
"verification_before_claim": 1.0,
|
|
120
|
+
"loud_failure": 1.0,
|
|
121
|
+
"honest_uncertainty": 1.0,
|
|
122
|
+
"paper_trail": 1.0,
|
|
123
|
+
"diligent_execution": 1.0,
|
|
124
|
+
}
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
def calculate_trust(self) -> float:
|
|
128
|
+
"""Calculate current trust with decay."""
|
|
129
|
+
if self.sessions_completed == 0:
|
|
130
|
+
return TrustLevel.MODERATE
|
|
131
|
+
|
|
132
|
+
# Performance factor
|
|
133
|
+
if self.total_actions > 0:
|
|
134
|
+
performance = 1.0 - (self.total_violations / self.total_actions)
|
|
135
|
+
else:
|
|
136
|
+
performance = TrustLevel.MODERATE
|
|
137
|
+
|
|
138
|
+
# Behavior average
|
|
139
|
+
behavior_avg = (
|
|
140
|
+
sum(self.behavior_trust.values()) / len(self.behavior_trust)
|
|
141
|
+
if self.behavior_trust
|
|
142
|
+
else 1.0
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
# Time decay
|
|
146
|
+
decay = self._calculate_decay()
|
|
147
|
+
|
|
148
|
+
# Streak bonus/penalty
|
|
149
|
+
streak_bonus = min(0.1, self.consecutive_clean_sessions * 0.02)
|
|
150
|
+
|
|
151
|
+
# Combine
|
|
152
|
+
raw_trust = performance * 0.4 + behavior_avg * 0.4 + TrustLevel.MODERATE * 0.2
|
|
153
|
+
self.current_trust = max(0.0, min(1.0, raw_trust * decay + streak_bonus))
|
|
154
|
+
|
|
155
|
+
return self.current_trust
|
|
156
|
+
|
|
157
|
+
def _calculate_decay(self) -> float:
|
|
158
|
+
"""Calculate trust decay based on time since last session."""
|
|
159
|
+
if not self.last_session:
|
|
160
|
+
return 1.0
|
|
161
|
+
|
|
162
|
+
now = datetime.now(timezone.utc)
|
|
163
|
+
if self.last_session.tzinfo is None:
|
|
164
|
+
last = self.last_session.replace(tzinfo=timezone.utc)
|
|
165
|
+
else:
|
|
166
|
+
last = self.last_session
|
|
167
|
+
|
|
168
|
+
days_since = (now - last).total_seconds() / (24 * 60 * 60)
|
|
169
|
+
decay = math.exp(-0.693 * days_since / self.trust_half_life_days)
|
|
170
|
+
return max(0.5, decay)
|
|
171
|
+
|
|
172
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
173
|
+
"""Convert to dictionary for storage."""
|
|
174
|
+
return {
|
|
175
|
+
"agent_id": self.agent_id,
|
|
176
|
+
"current_trust": self.current_trust,
|
|
177
|
+
"sessions_completed": self.sessions_completed,
|
|
178
|
+
"total_actions": self.total_actions,
|
|
179
|
+
"total_violations": self.total_violations,
|
|
180
|
+
"consecutive_clean_sessions": self.consecutive_clean_sessions,
|
|
181
|
+
"last_session": self.last_session.isoformat()
|
|
182
|
+
if self.last_session
|
|
183
|
+
else None,
|
|
184
|
+
"trust_half_life_days": self.trust_half_life_days,
|
|
185
|
+
"behavior_trust": self.behavior_trust,
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
@classmethod
|
|
189
|
+
def from_dict(cls, data: Dict[str, Any]) -> "AgentTrustProfile":
|
|
190
|
+
"""Create from dictionary."""
|
|
191
|
+
last_session = data.get("last_session")
|
|
192
|
+
if isinstance(last_session, str):
|
|
193
|
+
last_session = datetime.fromisoformat(last_session)
|
|
194
|
+
|
|
195
|
+
return cls(
|
|
196
|
+
agent_id=data["agent_id"],
|
|
197
|
+
current_trust=data.get("current_trust", TrustLevel.MODERATE),
|
|
198
|
+
sessions_completed=data.get("sessions_completed", 0),
|
|
199
|
+
total_actions=data.get("total_actions", 0),
|
|
200
|
+
total_violations=data.get("total_violations", 0),
|
|
201
|
+
consecutive_clean_sessions=data.get("consecutive_clean_sessions", 0),
|
|
202
|
+
last_session=last_session,
|
|
203
|
+
trust_half_life_days=data.get("trust_half_life_days", 30),
|
|
204
|
+
behavior_trust=data.get("behavior_trust", {}),
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
@dataclass
|
|
209
|
+
class TrustScoredItem(ScoredItem):
|
|
210
|
+
"""Extended scored item with trust information."""
|
|
211
|
+
|
|
212
|
+
trust_score: float = 1.0
|
|
213
|
+
source_agent: Optional[str] = None
|
|
214
|
+
trust_level: str = "MODERATE"
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
@dataclass
|
|
218
|
+
class AgentTrustContext:
|
|
219
|
+
"""
|
|
220
|
+
Lightweight trust context for passing to scoring functions.
|
|
221
|
+
|
|
222
|
+
Distinct from AgentTrustProfile - this is a simplified view
|
|
223
|
+
used during retrieval operations.
|
|
224
|
+
"""
|
|
225
|
+
|
|
226
|
+
agent_id: str
|
|
227
|
+
trust_score: float = TrustLevel.MODERATE
|
|
228
|
+
trust_behaviors: Dict[str, float] = field(default_factory=dict)
|
|
229
|
+
|
|
230
|
+
@classmethod
|
|
231
|
+
def from_profile(cls, profile: AgentTrustProfile) -> "AgentTrustContext":
|
|
232
|
+
"""Create context from full profile."""
|
|
233
|
+
return cls(
|
|
234
|
+
agent_id=profile.agent_id,
|
|
235
|
+
trust_score=profile.current_trust,
|
|
236
|
+
trust_behaviors=dict(profile.behavior_trust),
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
@property
|
|
240
|
+
def trust_level(self) -> str:
|
|
241
|
+
"""Get human-readable trust level."""
|
|
242
|
+
return TrustLevel.label(self.trust_score)
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
class TrustAwareScorer(MemoryScorer):
|
|
246
|
+
"""
|
|
247
|
+
Memory scorer that incorporates trust patterns.
|
|
248
|
+
|
|
249
|
+
Extends base MemoryScorer to weight memories by:
|
|
250
|
+
- Source agent's trust level
|
|
251
|
+
- Memory's verification status
|
|
252
|
+
- Trust-relevant metadata
|
|
253
|
+
"""
|
|
254
|
+
|
|
255
|
+
def __init__(
|
|
256
|
+
self,
|
|
257
|
+
weights: Optional[TrustWeights] = None,
|
|
258
|
+
recency_half_life_days: float = 30.0,
|
|
259
|
+
trust_profiles: Optional[Dict[str, AgentTrustProfile]] = None,
|
|
260
|
+
default_trust: float = TrustLevel.MODERATE,
|
|
261
|
+
):
|
|
262
|
+
# Convert TrustWeights to base ScoringWeights for parent
|
|
263
|
+
tw = weights or TrustWeights()
|
|
264
|
+
base_weights = ScoringWeights(
|
|
265
|
+
similarity=tw.similarity,
|
|
266
|
+
recency=tw.recency,
|
|
267
|
+
success_rate=tw.success_rate,
|
|
268
|
+
confidence=tw.confidence,
|
|
269
|
+
)
|
|
270
|
+
super().__init__(
|
|
271
|
+
weights=base_weights, recency_half_life_days=recency_half_life_days
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
self.trust_weights = tw
|
|
275
|
+
self.trust_profiles = trust_profiles or {}
|
|
276
|
+
self.default_trust = default_trust
|
|
277
|
+
|
|
278
|
+
def set_trust_profile(self, agent_id: str, profile: AgentTrustProfile) -> None:
|
|
279
|
+
"""Set trust profile for an agent."""
|
|
280
|
+
self.trust_profiles[agent_id] = profile
|
|
281
|
+
|
|
282
|
+
def get_agent_trust(self, agent_id: str) -> float:
|
|
283
|
+
"""Get trust score for an agent."""
|
|
284
|
+
if agent_id in self.trust_profiles:
|
|
285
|
+
return self.trust_profiles[agent_id].calculate_trust()
|
|
286
|
+
return self.default_trust
|
|
287
|
+
|
|
288
|
+
def score_heuristics_with_trust(
|
|
289
|
+
self,
|
|
290
|
+
heuristics: List[Heuristic],
|
|
291
|
+
similarities: Optional[List[float]] = None,
|
|
292
|
+
requesting_agent: Optional[str] = None,
|
|
293
|
+
) -> List[TrustScoredItem]:
|
|
294
|
+
"""
|
|
295
|
+
Score heuristics including trust factor.
|
|
296
|
+
|
|
297
|
+
Args:
|
|
298
|
+
heuristics: List of heuristics to score
|
|
299
|
+
similarities: Optional pre-computed similarity scores
|
|
300
|
+
requesting_agent: Agent requesting the memories (for trust context)
|
|
301
|
+
|
|
302
|
+
Returns:
|
|
303
|
+
Sorted list of TrustScoredItems
|
|
304
|
+
"""
|
|
305
|
+
if not heuristics:
|
|
306
|
+
return []
|
|
307
|
+
|
|
308
|
+
similarities = similarities or [1.0] * len(heuristics)
|
|
309
|
+
scored = []
|
|
310
|
+
|
|
311
|
+
for h, sim in zip(heuristics, similarities, strict=False):
|
|
312
|
+
recency = self._compute_recency_score(h.last_validated)
|
|
313
|
+
success = h.success_rate
|
|
314
|
+
confidence = h.confidence
|
|
315
|
+
|
|
316
|
+
# Get trust for source agent
|
|
317
|
+
source_trust = self.get_agent_trust(h.agent)
|
|
318
|
+
|
|
319
|
+
# Check if memory has verification metadata
|
|
320
|
+
verified = h.metadata.get("verified", False)
|
|
321
|
+
if verified:
|
|
322
|
+
source_trust = min(1.0, source_trust * 1.1) # 10% boost for verified
|
|
323
|
+
|
|
324
|
+
# Compute weighted score
|
|
325
|
+
total = (
|
|
326
|
+
self.trust_weights.similarity * sim
|
|
327
|
+
+ self.trust_weights.recency * recency
|
|
328
|
+
+ self.trust_weights.success_rate * success
|
|
329
|
+
+ self.trust_weights.confidence * confidence
|
|
330
|
+
+ self.trust_weights.trust * source_trust
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
scored.append(
|
|
334
|
+
TrustScoredItem(
|
|
335
|
+
item=h,
|
|
336
|
+
score=total,
|
|
337
|
+
similarity_score=sim,
|
|
338
|
+
recency_score=recency,
|
|
339
|
+
success_score=success,
|
|
340
|
+
confidence_score=confidence,
|
|
341
|
+
trust_score=source_trust,
|
|
342
|
+
source_agent=h.agent,
|
|
343
|
+
trust_level=TrustLevel.label(source_trust),
|
|
344
|
+
)
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
return sorted(scored, key=lambda x: -x.score)
|
|
348
|
+
|
|
349
|
+
def score_outcomes_with_trust(
|
|
350
|
+
self,
|
|
351
|
+
outcomes: List[Outcome],
|
|
352
|
+
similarities: Optional[List[float]] = None,
|
|
353
|
+
) -> List[TrustScoredItem]:
|
|
354
|
+
"""Score outcomes including trust factor."""
|
|
355
|
+
if not outcomes:
|
|
356
|
+
return []
|
|
357
|
+
|
|
358
|
+
similarities = similarities or [1.0] * len(outcomes)
|
|
359
|
+
scored = []
|
|
360
|
+
|
|
361
|
+
for o, sim in zip(outcomes, similarities, strict=False):
|
|
362
|
+
recency = self._compute_recency_score(o.timestamp)
|
|
363
|
+
success = 1.0 if o.success else 0.3
|
|
364
|
+
confidence = 1.0
|
|
365
|
+
|
|
366
|
+
source_trust = self.get_agent_trust(o.agent)
|
|
367
|
+
|
|
368
|
+
# Boost trust for outcomes with user feedback
|
|
369
|
+
if o.user_feedback:
|
|
370
|
+
source_trust = min(1.0, source_trust * 1.05)
|
|
371
|
+
|
|
372
|
+
total = (
|
|
373
|
+
self.trust_weights.similarity * sim
|
|
374
|
+
+ self.trust_weights.recency * recency
|
|
375
|
+
+ self.trust_weights.success_rate * success
|
|
376
|
+
+ self.trust_weights.confidence * confidence
|
|
377
|
+
+ self.trust_weights.trust * source_trust
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
scored.append(
|
|
381
|
+
TrustScoredItem(
|
|
382
|
+
item=o,
|
|
383
|
+
score=total,
|
|
384
|
+
similarity_score=sim,
|
|
385
|
+
recency_score=recency,
|
|
386
|
+
success_score=success,
|
|
387
|
+
confidence_score=confidence,
|
|
388
|
+
trust_score=source_trust,
|
|
389
|
+
source_agent=o.agent,
|
|
390
|
+
trust_level=TrustLevel.label(source_trust),
|
|
391
|
+
)
|
|
392
|
+
)
|
|
393
|
+
|
|
394
|
+
return sorted(scored, key=lambda x: -x.score)
|
|
395
|
+
|
|
396
|
+
def score_anti_patterns_with_trust(
|
|
397
|
+
self,
|
|
398
|
+
anti_patterns: List[AntiPattern],
|
|
399
|
+
similarities: Optional[List[float]] = None,
|
|
400
|
+
) -> List[TrustScoredItem]:
|
|
401
|
+
"""
|
|
402
|
+
Score anti-patterns including trust factor.
|
|
403
|
+
|
|
404
|
+
Anti-patterns from high-trust agents are MORE important (they've
|
|
405
|
+
learned from experience), so trust boosts rather than reduces score.
|
|
406
|
+
"""
|
|
407
|
+
if not anti_patterns:
|
|
408
|
+
return []
|
|
409
|
+
|
|
410
|
+
similarities = similarities or [1.0] * len(anti_patterns)
|
|
411
|
+
scored = []
|
|
412
|
+
|
|
413
|
+
for ap, sim in zip(anti_patterns, similarities, strict=False):
|
|
414
|
+
recency = self._compute_recency_score(ap.last_seen)
|
|
415
|
+
# More occurrences = more important
|
|
416
|
+
occurrence_score = min(ap.occurrence_count / 10.0, 1.0)
|
|
417
|
+
confidence = 1.0
|
|
418
|
+
|
|
419
|
+
source_trust = self.get_agent_trust(ap.agent)
|
|
420
|
+
|
|
421
|
+
# For anti-patterns, higher trust = more reliable warning
|
|
422
|
+
# Check if this came from a trust violation
|
|
423
|
+
from_violation = ap.metadata.get("from_trust_violation", False)
|
|
424
|
+
if from_violation:
|
|
425
|
+
source_trust = min(1.0, source_trust * 1.2) # 20% boost
|
|
426
|
+
|
|
427
|
+
total = (
|
|
428
|
+
self.trust_weights.similarity * sim
|
|
429
|
+
+ self.trust_weights.recency * recency
|
|
430
|
+
+ self.trust_weights.success_rate * occurrence_score
|
|
431
|
+
+ self.trust_weights.confidence * confidence
|
|
432
|
+
+ self.trust_weights.trust * source_trust
|
|
433
|
+
)
|
|
434
|
+
|
|
435
|
+
scored.append(
|
|
436
|
+
TrustScoredItem(
|
|
437
|
+
item=ap,
|
|
438
|
+
score=total,
|
|
439
|
+
similarity_score=sim,
|
|
440
|
+
recency_score=recency,
|
|
441
|
+
success_score=occurrence_score,
|
|
442
|
+
confidence_score=confidence,
|
|
443
|
+
trust_score=source_trust,
|
|
444
|
+
source_agent=ap.agent,
|
|
445
|
+
trust_level=TrustLevel.label(source_trust),
|
|
446
|
+
)
|
|
447
|
+
)
|
|
448
|
+
|
|
449
|
+
return sorted(scored, key=lambda x: -x.score)
|
|
450
|
+
|
|
451
|
+
def score_with_trust(
|
|
452
|
+
self,
|
|
453
|
+
memory_slice: MemorySlice,
|
|
454
|
+
similarities: Optional[Dict[str, List[float]]] = None,
|
|
455
|
+
) -> Dict[str, List[TrustScoredItem]]:
|
|
456
|
+
"""
|
|
457
|
+
Score all memories in a slice with trust integration.
|
|
458
|
+
|
|
459
|
+
Args:
|
|
460
|
+
memory_slice: Memories to score
|
|
461
|
+
similarities: Optional dict of similarity scores by type
|
|
462
|
+
|
|
463
|
+
Returns:
|
|
464
|
+
Dict with scored items by type
|
|
465
|
+
"""
|
|
466
|
+
similarities = similarities or {}
|
|
467
|
+
|
|
468
|
+
return {
|
|
469
|
+
"heuristics": self.score_heuristics_with_trust(
|
|
470
|
+
memory_slice.heuristics,
|
|
471
|
+
similarities.get("heuristics"),
|
|
472
|
+
),
|
|
473
|
+
"outcomes": self.score_outcomes_with_trust(
|
|
474
|
+
memory_slice.outcomes,
|
|
475
|
+
similarities.get("outcomes"),
|
|
476
|
+
),
|
|
477
|
+
"anti_patterns": self.score_anti_patterns_with_trust(
|
|
478
|
+
memory_slice.anti_patterns,
|
|
479
|
+
similarities.get("anti_patterns"),
|
|
480
|
+
),
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
class TrustPatternStore:
|
|
485
|
+
"""
|
|
486
|
+
Stores and retrieves trust patterns in ALMA memory.
|
|
487
|
+
|
|
488
|
+
Enables:
|
|
489
|
+
- Storing trust violations as AntiPatterns
|
|
490
|
+
- Storing successful verification patterns as Heuristics
|
|
491
|
+
- Retrieving trust-relevant memories for a task
|
|
492
|
+
"""
|
|
493
|
+
|
|
494
|
+
def __init__(self, alma_core: Any): # ALMA instance
|
|
495
|
+
self.alma = alma_core
|
|
496
|
+
|
|
497
|
+
async def store_trust_violation(
|
|
498
|
+
self,
|
|
499
|
+
agent_id: str,
|
|
500
|
+
project_id: str,
|
|
501
|
+
violation_type: str,
|
|
502
|
+
description: str,
|
|
503
|
+
severity: str,
|
|
504
|
+
remediation: str,
|
|
505
|
+
context: Optional[Dict[str, Any]] = None,
|
|
506
|
+
) -> None:
|
|
507
|
+
"""
|
|
508
|
+
Store a trust violation as an ALMA AntiPattern.
|
|
509
|
+
|
|
510
|
+
This allows trust violations to be retrieved as warnings
|
|
511
|
+
for similar future tasks.
|
|
512
|
+
"""
|
|
513
|
+
anti_pattern_data = {
|
|
514
|
+
"pattern": f"Trust violation: {violation_type}",
|
|
515
|
+
"why_bad": description,
|
|
516
|
+
"better_alternative": remediation,
|
|
517
|
+
"metadata": {
|
|
518
|
+
"from_trust_violation": True,
|
|
519
|
+
"severity": severity,
|
|
520
|
+
"original_context": context or {},
|
|
521
|
+
},
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
# Use ALMA's learn method to store
|
|
525
|
+
await self.alma.learn(
|
|
526
|
+
task_type="trust_enforcement",
|
|
527
|
+
strategy=f"Avoid: {violation_type}",
|
|
528
|
+
outcome="failure",
|
|
529
|
+
details=anti_pattern_data,
|
|
530
|
+
agent=agent_id,
|
|
531
|
+
project_id=project_id,
|
|
532
|
+
)
|
|
533
|
+
|
|
534
|
+
logger.info(
|
|
535
|
+
f"Stored trust violation as anti-pattern: {violation_type} "
|
|
536
|
+
f"for agent {agent_id}"
|
|
537
|
+
)
|
|
538
|
+
|
|
539
|
+
async def store_verification_pattern(
|
|
540
|
+
self,
|
|
541
|
+
agent_id: str,
|
|
542
|
+
project_id: str,
|
|
543
|
+
task_type: str,
|
|
544
|
+
verification_strategy: str,
|
|
545
|
+
evidence_types: List[str],
|
|
546
|
+
verification_rate: float,
|
|
547
|
+
) -> None:
|
|
548
|
+
"""
|
|
549
|
+
Store a successful verification pattern as an ALMA Heuristic.
|
|
550
|
+
|
|
551
|
+
This allows effective verification strategies to be retrieved
|
|
552
|
+
for similar future tasks.
|
|
553
|
+
"""
|
|
554
|
+
await self.alma.learn(
|
|
555
|
+
task_type=task_type,
|
|
556
|
+
strategy=verification_strategy,
|
|
557
|
+
outcome="success",
|
|
558
|
+
details={
|
|
559
|
+
"evidence_types_used": evidence_types,
|
|
560
|
+
"verification_rate": verification_rate,
|
|
561
|
+
"metadata": {
|
|
562
|
+
"is_verification_pattern": True,
|
|
563
|
+
},
|
|
564
|
+
},
|
|
565
|
+
agent=agent_id,
|
|
566
|
+
project_id=project_id,
|
|
567
|
+
)
|
|
568
|
+
|
|
569
|
+
logger.info(
|
|
570
|
+
f"Stored verification pattern for {task_type}: "
|
|
571
|
+
f"{verification_strategy} ({verification_rate:.0%} rate)"
|
|
572
|
+
)
|
|
573
|
+
|
|
574
|
+
async def store_trust_profile(
|
|
575
|
+
self,
|
|
576
|
+
profile: AgentTrustProfile,
|
|
577
|
+
project_id: str,
|
|
578
|
+
) -> None:
|
|
579
|
+
"""Store agent trust profile as domain knowledge."""
|
|
580
|
+
await self.alma.add_knowledge(
|
|
581
|
+
domain="trust_profiles",
|
|
582
|
+
fact=profile.to_dict(),
|
|
583
|
+
source="veritas_trust_evolution",
|
|
584
|
+
confidence=1.0,
|
|
585
|
+
agent="trust_system",
|
|
586
|
+
project_id=project_id,
|
|
587
|
+
)
|
|
588
|
+
|
|
589
|
+
async def retrieve_trust_profile(
|
|
590
|
+
self,
|
|
591
|
+
agent_id: str,
|
|
592
|
+
project_id: str,
|
|
593
|
+
) -> Optional[AgentTrustProfile]:
|
|
594
|
+
"""Retrieve agent trust profile from domain knowledge."""
|
|
595
|
+
memories = await self.alma.retrieve(
|
|
596
|
+
task=f"trust_profile:{agent_id}",
|
|
597
|
+
agent="trust_system",
|
|
598
|
+
project_id=project_id,
|
|
599
|
+
)
|
|
600
|
+
|
|
601
|
+
for knowledge in memories.domain_knowledge:
|
|
602
|
+
if knowledge.domain == "trust_profiles":
|
|
603
|
+
fact = knowledge.fact
|
|
604
|
+
if isinstance(fact, dict) and fact.get("agent_id") == agent_id:
|
|
605
|
+
return AgentTrustProfile.from_dict(fact)
|
|
606
|
+
|
|
607
|
+
return None
|
|
608
|
+
|
|
609
|
+
async def retrieve_trust_warnings(
|
|
610
|
+
self,
|
|
611
|
+
task_description: str,
|
|
612
|
+
agent_id: str,
|
|
613
|
+
project_id: str,
|
|
614
|
+
) -> List[str]:
|
|
615
|
+
"""
|
|
616
|
+
Retrieve trust-related warnings for a task.
|
|
617
|
+
|
|
618
|
+
Returns warnings based on past trust violations
|
|
619
|
+
that are relevant to the current task.
|
|
620
|
+
"""
|
|
621
|
+
memories = await self.alma.retrieve(
|
|
622
|
+
task=f"trust_verification:{task_description}",
|
|
623
|
+
agent=agent_id,
|
|
624
|
+
project_id=project_id,
|
|
625
|
+
include_anti_patterns=True,
|
|
626
|
+
)
|
|
627
|
+
|
|
628
|
+
warnings = []
|
|
629
|
+
for ap in memories.anti_patterns:
|
|
630
|
+
if ap.metadata.get("from_trust_violation"):
|
|
631
|
+
if ap.occurrence_count >= 2:
|
|
632
|
+
warnings.append(
|
|
633
|
+
f"Repeated trust issue: {ap.pattern}. "
|
|
634
|
+
f"Suggestion: {ap.better_alternative}"
|
|
635
|
+
)
|
|
636
|
+
|
|
637
|
+
return warnings
|