alma-memory 0.2.0__py3-none-any.whl → 0.4.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 +76 -1
- alma/confidence/__init__.py +47 -0
- alma/confidence/engine.py +506 -0
- alma/confidence/types.py +331 -0
- alma/domains/__init__.py +30 -0
- alma/domains/factory.py +356 -0
- alma/domains/schemas.py +434 -0
- alma/domains/types.py +268 -0
- alma/initializer/__init__.py +37 -0
- alma/initializer/initializer.py +410 -0
- alma/initializer/types.py +242 -0
- alma/progress/__init__.py +21 -0
- alma/progress/tracker.py +601 -0
- alma/progress/types.py +254 -0
- alma/session/__init__.py +19 -0
- alma/session/manager.py +399 -0
- alma/session/types.py +287 -0
- alma/storage/azure_cosmos.py +6 -0
- alma/storage/sqlite_local.py +101 -0
- alma_memory-0.4.0.dist-info/METADATA +488 -0
- {alma_memory-0.2.0.dist-info → alma_memory-0.4.0.dist-info}/RECORD +23 -7
- alma_memory-0.2.0.dist-info/METADATA +0 -327
- {alma_memory-0.2.0.dist-info → alma_memory-0.4.0.dist-info}/WHEEL +0 -0
- {alma_memory-0.2.0.dist-info → alma_memory-0.4.0.dist-info}/top_level.txt +0 -0
alma/domains/schemas.py
ADDED
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pre-built Domain Schemas.
|
|
3
|
+
|
|
4
|
+
Standard domain schemas for common use cases.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from alma.domains.types import DomainSchema, EntityType, RelationshipType
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_coding_schema() -> DomainSchema:
|
|
11
|
+
"""
|
|
12
|
+
Pre-built schema for coding workflows.
|
|
13
|
+
|
|
14
|
+
This is the formalized version of ALMA's original Helena/Victor schema.
|
|
15
|
+
Suitable for: Frontend testing, backend testing, general development.
|
|
16
|
+
"""
|
|
17
|
+
schema = DomainSchema.create(
|
|
18
|
+
name="coding",
|
|
19
|
+
description="Memory schema for software development workflows",
|
|
20
|
+
learning_categories=[
|
|
21
|
+
"testing_strategies",
|
|
22
|
+
"selector_patterns",
|
|
23
|
+
"api_design_patterns",
|
|
24
|
+
"error_handling",
|
|
25
|
+
"performance_optimization",
|
|
26
|
+
"debugging_techniques",
|
|
27
|
+
"code_review_patterns",
|
|
28
|
+
"refactoring_strategies",
|
|
29
|
+
],
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
# Entity types
|
|
33
|
+
schema.add_entity_type(
|
|
34
|
+
name="feature",
|
|
35
|
+
description="A software feature or capability",
|
|
36
|
+
attributes=["status", "tests", "files", "priority", "owner"],
|
|
37
|
+
)
|
|
38
|
+
schema.add_entity_type(
|
|
39
|
+
name="bug",
|
|
40
|
+
description="A software defect or issue",
|
|
41
|
+
attributes=["severity", "reproduction_steps", "fix", "status", "root_cause"],
|
|
42
|
+
)
|
|
43
|
+
schema.add_entity_type(
|
|
44
|
+
name="test",
|
|
45
|
+
description="A test case or test suite",
|
|
46
|
+
attributes=["type", "status", "coverage", "flaky", "last_run"],
|
|
47
|
+
)
|
|
48
|
+
schema.add_entity_type(
|
|
49
|
+
name="component",
|
|
50
|
+
description="A code component or module",
|
|
51
|
+
attributes=["path", "type", "dependencies", "tests"],
|
|
52
|
+
)
|
|
53
|
+
schema.add_entity_type(
|
|
54
|
+
name="api_endpoint",
|
|
55
|
+
description="An API endpoint",
|
|
56
|
+
attributes=["method", "path", "request_schema", "response_schema", "auth"],
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
# Relationships
|
|
60
|
+
schema.add_relationship_type(
|
|
61
|
+
name="tests",
|
|
62
|
+
description="Test covers a feature or component",
|
|
63
|
+
source_type="test",
|
|
64
|
+
target_type="feature",
|
|
65
|
+
)
|
|
66
|
+
schema.add_relationship_type(
|
|
67
|
+
name="fixes",
|
|
68
|
+
description="Commit or change fixes a bug",
|
|
69
|
+
source_type="feature",
|
|
70
|
+
target_type="bug",
|
|
71
|
+
)
|
|
72
|
+
schema.add_relationship_type(
|
|
73
|
+
name="depends_on",
|
|
74
|
+
description="Component depends on another component",
|
|
75
|
+
source_type="component",
|
|
76
|
+
target_type="component",
|
|
77
|
+
)
|
|
78
|
+
schema.add_relationship_type(
|
|
79
|
+
name="implements",
|
|
80
|
+
description="Component implements an API endpoint",
|
|
81
|
+
source_type="component",
|
|
82
|
+
target_type="api_endpoint",
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
return schema
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def get_research_schema() -> DomainSchema:
|
|
89
|
+
"""
|
|
90
|
+
Pre-built schema for research workflows.
|
|
91
|
+
|
|
92
|
+
Suitable for: Literature review, hypothesis testing, academic research.
|
|
93
|
+
"""
|
|
94
|
+
schema = DomainSchema.create(
|
|
95
|
+
name="research",
|
|
96
|
+
description="Memory schema for research and academic workflows",
|
|
97
|
+
learning_categories=[
|
|
98
|
+
"literature_review_patterns",
|
|
99
|
+
"methodology_selection",
|
|
100
|
+
"data_analysis_strategies",
|
|
101
|
+
"citation_patterns",
|
|
102
|
+
"hypothesis_formulation",
|
|
103
|
+
"experiment_design",
|
|
104
|
+
"peer_review_patterns",
|
|
105
|
+
"synthesis_techniques",
|
|
106
|
+
],
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
# Entity types
|
|
110
|
+
schema.add_entity_type(
|
|
111
|
+
name="paper",
|
|
112
|
+
description="An academic paper or article",
|
|
113
|
+
attributes=["title", "authors", "year", "citations", "abstract", "venue", "doi"],
|
|
114
|
+
)
|
|
115
|
+
schema.add_entity_type(
|
|
116
|
+
name="hypothesis",
|
|
117
|
+
description="A research hypothesis",
|
|
118
|
+
attributes=["statement", "confidence", "evidence_for", "evidence_against", "status"],
|
|
119
|
+
)
|
|
120
|
+
schema.add_entity_type(
|
|
121
|
+
name="experiment",
|
|
122
|
+
description="An experiment or study",
|
|
123
|
+
attributes=["method", "results", "conclusions", "status", "sample_size"],
|
|
124
|
+
)
|
|
125
|
+
schema.add_entity_type(
|
|
126
|
+
name="dataset",
|
|
127
|
+
description="A dataset used in research",
|
|
128
|
+
attributes=["name", "size", "format", "source", "license"],
|
|
129
|
+
)
|
|
130
|
+
schema.add_entity_type(
|
|
131
|
+
name="finding",
|
|
132
|
+
description="A research finding or insight",
|
|
133
|
+
attributes=["summary", "significance", "confidence", "supporting_evidence"],
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
# Relationships
|
|
137
|
+
schema.add_relationship_type(
|
|
138
|
+
name="cites",
|
|
139
|
+
description="Paper cites another paper",
|
|
140
|
+
source_type="paper",
|
|
141
|
+
target_type="paper",
|
|
142
|
+
)
|
|
143
|
+
schema.add_relationship_type(
|
|
144
|
+
name="tests",
|
|
145
|
+
description="Experiment tests a hypothesis",
|
|
146
|
+
source_type="experiment",
|
|
147
|
+
target_type="hypothesis",
|
|
148
|
+
)
|
|
149
|
+
schema.add_relationship_type(
|
|
150
|
+
name="uses",
|
|
151
|
+
description="Experiment uses a dataset",
|
|
152
|
+
source_type="experiment",
|
|
153
|
+
target_type="dataset",
|
|
154
|
+
)
|
|
155
|
+
schema.add_relationship_type(
|
|
156
|
+
name="supports",
|
|
157
|
+
description="Finding supports a hypothesis",
|
|
158
|
+
source_type="finding",
|
|
159
|
+
target_type="hypothesis",
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
return schema
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def get_sales_schema() -> DomainSchema:
|
|
166
|
+
"""
|
|
167
|
+
Pre-built schema for sales workflows.
|
|
168
|
+
|
|
169
|
+
Suitable for: Lead management, customer conversations, deal tracking.
|
|
170
|
+
"""
|
|
171
|
+
schema = DomainSchema.create(
|
|
172
|
+
name="sales",
|
|
173
|
+
description="Memory schema for sales and customer engagement workflows",
|
|
174
|
+
learning_categories=[
|
|
175
|
+
"objection_handling",
|
|
176
|
+
"closing_techniques",
|
|
177
|
+
"qualification_patterns",
|
|
178
|
+
"follow_up_timing",
|
|
179
|
+
"value_proposition",
|
|
180
|
+
"discovery_questions",
|
|
181
|
+
"relationship_building",
|
|
182
|
+
"negotiation_strategies",
|
|
183
|
+
],
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
# Entity types
|
|
187
|
+
schema.add_entity_type(
|
|
188
|
+
name="lead",
|
|
189
|
+
description="A potential customer or prospect",
|
|
190
|
+
attributes=["stage", "value", "next_action", "source", "company", "title"],
|
|
191
|
+
)
|
|
192
|
+
schema.add_entity_type(
|
|
193
|
+
name="objection",
|
|
194
|
+
description="A customer objection or concern",
|
|
195
|
+
attributes=["type", "response", "outcome", "context"],
|
|
196
|
+
)
|
|
197
|
+
schema.add_entity_type(
|
|
198
|
+
name="conversation",
|
|
199
|
+
description="A customer interaction",
|
|
200
|
+
attributes=["channel", "sentiment", "result", "summary", "follow_up"],
|
|
201
|
+
)
|
|
202
|
+
schema.add_entity_type(
|
|
203
|
+
name="deal",
|
|
204
|
+
description="A sales deal or opportunity",
|
|
205
|
+
attributes=["stage", "value", "close_date", "probability", "stakeholders"],
|
|
206
|
+
)
|
|
207
|
+
schema.add_entity_type(
|
|
208
|
+
name="product",
|
|
209
|
+
description="A product or service being sold",
|
|
210
|
+
attributes=["name", "price", "features", "competitors"],
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
# Relationships
|
|
214
|
+
schema.add_relationship_type(
|
|
215
|
+
name="converts_to",
|
|
216
|
+
description="Lead converts to a deal",
|
|
217
|
+
source_type="lead",
|
|
218
|
+
target_type="deal",
|
|
219
|
+
)
|
|
220
|
+
schema.add_relationship_type(
|
|
221
|
+
name="raised",
|
|
222
|
+
description="Lead raised an objection",
|
|
223
|
+
source_type="lead",
|
|
224
|
+
target_type="objection",
|
|
225
|
+
)
|
|
226
|
+
schema.add_relationship_type(
|
|
227
|
+
name="had",
|
|
228
|
+
description="Lead had a conversation",
|
|
229
|
+
source_type="lead",
|
|
230
|
+
target_type="conversation",
|
|
231
|
+
)
|
|
232
|
+
schema.add_relationship_type(
|
|
233
|
+
name="interested_in",
|
|
234
|
+
description="Lead is interested in a product",
|
|
235
|
+
source_type="lead",
|
|
236
|
+
target_type="product",
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
return schema
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def get_general_schema() -> DomainSchema:
|
|
243
|
+
"""
|
|
244
|
+
Minimal schema for general-purpose agents.
|
|
245
|
+
|
|
246
|
+
This is a flexible schema that can be extended for any domain.
|
|
247
|
+
Suitable for: General assistants, tool-using agents, custom workflows.
|
|
248
|
+
"""
|
|
249
|
+
schema = DomainSchema.create(
|
|
250
|
+
name="general",
|
|
251
|
+
description="Minimal, flexible schema for general-purpose agents",
|
|
252
|
+
learning_categories=[
|
|
253
|
+
"task_patterns",
|
|
254
|
+
"error_recovery",
|
|
255
|
+
"tool_usage",
|
|
256
|
+
"efficiency_patterns",
|
|
257
|
+
"user_preferences",
|
|
258
|
+
"context_switching",
|
|
259
|
+
],
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
# Entity types (minimal but extensible)
|
|
263
|
+
schema.add_entity_type(
|
|
264
|
+
name="task",
|
|
265
|
+
description="A unit of work to be completed",
|
|
266
|
+
attributes=["title", "status", "priority", "category"],
|
|
267
|
+
)
|
|
268
|
+
schema.add_entity_type(
|
|
269
|
+
name="resource",
|
|
270
|
+
description="A resource used or created",
|
|
271
|
+
attributes=["type", "path", "status", "metadata"],
|
|
272
|
+
)
|
|
273
|
+
schema.add_entity_type(
|
|
274
|
+
name="goal",
|
|
275
|
+
description="An objective or target",
|
|
276
|
+
attributes=["description", "status", "deadline", "progress"],
|
|
277
|
+
)
|
|
278
|
+
schema.add_entity_type(
|
|
279
|
+
name="context",
|
|
280
|
+
description="A context or environment state",
|
|
281
|
+
attributes=["name", "state", "active"],
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
# Relationships (minimal)
|
|
285
|
+
schema.add_relationship_type(
|
|
286
|
+
name="achieves",
|
|
287
|
+
description="Task contributes to a goal",
|
|
288
|
+
source_type="task",
|
|
289
|
+
target_type="goal",
|
|
290
|
+
)
|
|
291
|
+
schema.add_relationship_type(
|
|
292
|
+
name="uses",
|
|
293
|
+
description="Task uses a resource",
|
|
294
|
+
source_type="task",
|
|
295
|
+
target_type="resource",
|
|
296
|
+
)
|
|
297
|
+
schema.add_relationship_type(
|
|
298
|
+
name="requires",
|
|
299
|
+
description="Task requires a context",
|
|
300
|
+
source_type="task",
|
|
301
|
+
target_type="context",
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
return schema
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def get_customer_support_schema() -> DomainSchema:
|
|
308
|
+
"""
|
|
309
|
+
Pre-built schema for customer support workflows.
|
|
310
|
+
|
|
311
|
+
Suitable for: Ticket handling, escalation, knowledge base management.
|
|
312
|
+
"""
|
|
313
|
+
schema = DomainSchema.create(
|
|
314
|
+
name="customer_support",
|
|
315
|
+
description="Memory schema for customer support workflows",
|
|
316
|
+
learning_categories=[
|
|
317
|
+
"issue_classification",
|
|
318
|
+
"resolution_patterns",
|
|
319
|
+
"escalation_criteria",
|
|
320
|
+
"customer_sentiment",
|
|
321
|
+
"knowledge_retrieval",
|
|
322
|
+
"follow_up_patterns",
|
|
323
|
+
"edge_case_handling",
|
|
324
|
+
],
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
# Entity types
|
|
328
|
+
schema.add_entity_type(
|
|
329
|
+
name="ticket",
|
|
330
|
+
description="A customer support ticket",
|
|
331
|
+
attributes=["status", "priority", "category", "customer_id", "resolution"],
|
|
332
|
+
)
|
|
333
|
+
schema.add_entity_type(
|
|
334
|
+
name="article",
|
|
335
|
+
description="A knowledge base article",
|
|
336
|
+
attributes=["title", "content", "category", "views", "helpful_votes"],
|
|
337
|
+
)
|
|
338
|
+
schema.add_entity_type(
|
|
339
|
+
name="customer",
|
|
340
|
+
description="A customer profile",
|
|
341
|
+
attributes=["tier", "history", "sentiment", "preferences"],
|
|
342
|
+
)
|
|
343
|
+
schema.add_entity_type(
|
|
344
|
+
name="issue",
|
|
345
|
+
description="A known issue or problem",
|
|
346
|
+
attributes=["description", "status", "workaround", "affected_customers"],
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
# Relationships
|
|
350
|
+
schema.add_relationship_type(
|
|
351
|
+
name="resolves",
|
|
352
|
+
description="Article resolves a ticket",
|
|
353
|
+
source_type="article",
|
|
354
|
+
target_type="ticket",
|
|
355
|
+
)
|
|
356
|
+
schema.add_relationship_type(
|
|
357
|
+
name="submitted_by",
|
|
358
|
+
description="Ticket submitted by customer",
|
|
359
|
+
source_type="ticket",
|
|
360
|
+
target_type="customer",
|
|
361
|
+
)
|
|
362
|
+
schema.add_relationship_type(
|
|
363
|
+
name="related_to",
|
|
364
|
+
description="Ticket related to a known issue",
|
|
365
|
+
source_type="ticket",
|
|
366
|
+
target_type="issue",
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
return schema
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
def get_content_creation_schema() -> DomainSchema:
|
|
373
|
+
"""
|
|
374
|
+
Pre-built schema for content creation workflows.
|
|
375
|
+
|
|
376
|
+
Suitable for: Blog writing, social media, marketing content.
|
|
377
|
+
"""
|
|
378
|
+
schema = DomainSchema.create(
|
|
379
|
+
name="content_creation",
|
|
380
|
+
description="Memory schema for content creation workflows",
|
|
381
|
+
learning_categories=[
|
|
382
|
+
"writing_patterns",
|
|
383
|
+
"engagement_optimization",
|
|
384
|
+
"audience_targeting",
|
|
385
|
+
"seo_strategies",
|
|
386
|
+
"content_formatting",
|
|
387
|
+
"voice_and_tone",
|
|
388
|
+
"visual_content_patterns",
|
|
389
|
+
],
|
|
390
|
+
)
|
|
391
|
+
|
|
392
|
+
# Entity types
|
|
393
|
+
schema.add_entity_type(
|
|
394
|
+
name="content",
|
|
395
|
+
description="A piece of content",
|
|
396
|
+
attributes=["type", "title", "status", "platform", "performance_metrics"],
|
|
397
|
+
)
|
|
398
|
+
schema.add_entity_type(
|
|
399
|
+
name="audience",
|
|
400
|
+
description="A target audience segment",
|
|
401
|
+
attributes=["name", "demographics", "interests", "pain_points"],
|
|
402
|
+
)
|
|
403
|
+
schema.add_entity_type(
|
|
404
|
+
name="campaign",
|
|
405
|
+
description="A content campaign",
|
|
406
|
+
attributes=["name", "goal", "start_date", "end_date", "budget"],
|
|
407
|
+
)
|
|
408
|
+
schema.add_entity_type(
|
|
409
|
+
name="template",
|
|
410
|
+
description="A content template",
|
|
411
|
+
attributes=["type", "structure", "usage_count", "effectiveness"],
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
# Relationships
|
|
415
|
+
schema.add_relationship_type(
|
|
416
|
+
name="targets",
|
|
417
|
+
description="Content targets an audience",
|
|
418
|
+
source_type="content",
|
|
419
|
+
target_type="audience",
|
|
420
|
+
)
|
|
421
|
+
schema.add_relationship_type(
|
|
422
|
+
name="part_of",
|
|
423
|
+
description="Content is part of a campaign",
|
|
424
|
+
source_type="content",
|
|
425
|
+
target_type="campaign",
|
|
426
|
+
)
|
|
427
|
+
schema.add_relationship_type(
|
|
428
|
+
name="uses",
|
|
429
|
+
description="Content uses a template",
|
|
430
|
+
source_type="content",
|
|
431
|
+
target_type="template",
|
|
432
|
+
)
|
|
433
|
+
|
|
434
|
+
return schema
|
alma/domains/types.py
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Domain Memory Types.
|
|
3
|
+
|
|
4
|
+
Data models for domain-specific memory schemas.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass, field
|
|
8
|
+
from datetime import datetime, timezone
|
|
9
|
+
from typing import List, Dict, Any, Optional
|
|
10
|
+
import uuid
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class EntityType:
|
|
15
|
+
"""
|
|
16
|
+
A type of entity in a domain.
|
|
17
|
+
|
|
18
|
+
Entities are the "things" that agents work with in a domain.
|
|
19
|
+
For example: features, bugs, tests (coding), papers, hypotheses (research).
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
name: str # "feature", "test", "paper", "lead"
|
|
23
|
+
description: str
|
|
24
|
+
attributes: List[str] = field(default_factory=list) # ["status", "priority", "owner"]
|
|
25
|
+
|
|
26
|
+
# Optional schema validation
|
|
27
|
+
required_attributes: List[str] = field(default_factory=list)
|
|
28
|
+
attribute_types: Dict[str, str] = field(default_factory=dict) # attr -> "str", "int", "bool"
|
|
29
|
+
|
|
30
|
+
def validate_entity(self, entity: Dict[str, Any]) -> List[str]:
|
|
31
|
+
"""Validate an entity instance against this type."""
|
|
32
|
+
errors = []
|
|
33
|
+
for attr in self.required_attributes:
|
|
34
|
+
if attr not in entity:
|
|
35
|
+
errors.append(f"Missing required attribute: {attr}")
|
|
36
|
+
return errors
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@dataclass
|
|
40
|
+
class RelationshipType:
|
|
41
|
+
"""
|
|
42
|
+
A relationship between entities in a domain.
|
|
43
|
+
|
|
44
|
+
Relationships connect entities (e.g., "feature implements spec").
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
name: str # "implements", "blocks", "supports", "cites"
|
|
48
|
+
description: str
|
|
49
|
+
source_type: str # Entity type name
|
|
50
|
+
target_type: str # Entity type name
|
|
51
|
+
|
|
52
|
+
# Cardinality
|
|
53
|
+
many_to_many: bool = True
|
|
54
|
+
required: bool = False
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@dataclass
|
|
58
|
+
class DomainSchema:
|
|
59
|
+
"""
|
|
60
|
+
Defines memory structure for a specific domain.
|
|
61
|
+
|
|
62
|
+
A schema describes what entities exist in a domain, how they relate,
|
|
63
|
+
and what learning categories agents can use.
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
id: str
|
|
67
|
+
name: str # "coding", "research", "sales"
|
|
68
|
+
description: str
|
|
69
|
+
|
|
70
|
+
# What entities exist in this domain
|
|
71
|
+
entity_types: List[EntityType] = field(default_factory=list)
|
|
72
|
+
|
|
73
|
+
# What relationships between entities
|
|
74
|
+
relationship_types: List[RelationshipType] = field(default_factory=list)
|
|
75
|
+
|
|
76
|
+
# Learning categories (replaces hardcoded HELENA_CATEGORIES)
|
|
77
|
+
learning_categories: List[str] = field(default_factory=list)
|
|
78
|
+
|
|
79
|
+
# What can agents in this domain NOT learn (scoping)
|
|
80
|
+
excluded_categories: List[str] = field(default_factory=list)
|
|
81
|
+
|
|
82
|
+
# Domain-specific settings
|
|
83
|
+
min_occurrences_for_heuristic: int = 3
|
|
84
|
+
confidence_decay_days: float = 30.0
|
|
85
|
+
|
|
86
|
+
# Timestamps
|
|
87
|
+
created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
|
|
88
|
+
updated_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
|
|
89
|
+
|
|
90
|
+
# Extensible metadata
|
|
91
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
92
|
+
|
|
93
|
+
@classmethod
|
|
94
|
+
def create(
|
|
95
|
+
cls,
|
|
96
|
+
name: str,
|
|
97
|
+
description: str,
|
|
98
|
+
learning_categories: Optional[List[str]] = None,
|
|
99
|
+
**kwargs,
|
|
100
|
+
) -> "DomainSchema":
|
|
101
|
+
"""Factory method to create a new domain schema."""
|
|
102
|
+
return cls(
|
|
103
|
+
id=str(uuid.uuid4()),
|
|
104
|
+
name=name,
|
|
105
|
+
description=description,
|
|
106
|
+
learning_categories=learning_categories or [],
|
|
107
|
+
**kwargs,
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
def add_entity_type(
|
|
111
|
+
self,
|
|
112
|
+
name: str,
|
|
113
|
+
description: str,
|
|
114
|
+
attributes: Optional[List[str]] = None,
|
|
115
|
+
) -> EntityType:
|
|
116
|
+
"""Add an entity type to this schema."""
|
|
117
|
+
entity = EntityType(
|
|
118
|
+
name=name,
|
|
119
|
+
description=description,
|
|
120
|
+
attributes=attributes or [],
|
|
121
|
+
)
|
|
122
|
+
self.entity_types.append(entity)
|
|
123
|
+
self.updated_at = datetime.now(timezone.utc)
|
|
124
|
+
return entity
|
|
125
|
+
|
|
126
|
+
def add_relationship_type(
|
|
127
|
+
self,
|
|
128
|
+
name: str,
|
|
129
|
+
description: str,
|
|
130
|
+
source_type: str,
|
|
131
|
+
target_type: str,
|
|
132
|
+
) -> RelationshipType:
|
|
133
|
+
"""Add a relationship type to this schema."""
|
|
134
|
+
rel = RelationshipType(
|
|
135
|
+
name=name,
|
|
136
|
+
description=description,
|
|
137
|
+
source_type=source_type,
|
|
138
|
+
target_type=target_type,
|
|
139
|
+
)
|
|
140
|
+
self.relationship_types.append(rel)
|
|
141
|
+
self.updated_at = datetime.now(timezone.utc)
|
|
142
|
+
return rel
|
|
143
|
+
|
|
144
|
+
def add_learning_category(self, category: str) -> None:
|
|
145
|
+
"""Add a learning category."""
|
|
146
|
+
if category not in self.learning_categories:
|
|
147
|
+
self.learning_categories.append(category)
|
|
148
|
+
self.updated_at = datetime.now(timezone.utc)
|
|
149
|
+
|
|
150
|
+
def add_excluded_category(self, category: str) -> None:
|
|
151
|
+
"""Add an excluded category (agent cannot learn from this)."""
|
|
152
|
+
if category not in self.excluded_categories:
|
|
153
|
+
self.excluded_categories.append(category)
|
|
154
|
+
self.updated_at = datetime.now(timezone.utc)
|
|
155
|
+
|
|
156
|
+
def get_entity_type(self, name: str) -> Optional[EntityType]:
|
|
157
|
+
"""Get entity type by name."""
|
|
158
|
+
for entity in self.entity_types:
|
|
159
|
+
if entity.name == name:
|
|
160
|
+
return entity
|
|
161
|
+
return None
|
|
162
|
+
|
|
163
|
+
def get_relationship_type(self, name: str) -> Optional[RelationshipType]:
|
|
164
|
+
"""Get relationship type by name."""
|
|
165
|
+
for rel in self.relationship_types:
|
|
166
|
+
if rel.name == name:
|
|
167
|
+
return rel
|
|
168
|
+
return None
|
|
169
|
+
|
|
170
|
+
def is_category_allowed(self, category: str) -> bool:
|
|
171
|
+
"""Check if a learning category is allowed in this domain."""
|
|
172
|
+
if self.learning_categories and category not in self.learning_categories:
|
|
173
|
+
return False
|
|
174
|
+
if category in self.excluded_categories:
|
|
175
|
+
return False
|
|
176
|
+
return True
|
|
177
|
+
|
|
178
|
+
def validate(self) -> List[str]:
|
|
179
|
+
"""Validate the schema for consistency."""
|
|
180
|
+
errors = []
|
|
181
|
+
|
|
182
|
+
# Check relationship source/target types exist
|
|
183
|
+
entity_names = {e.name for e in self.entity_types}
|
|
184
|
+
for rel in self.relationship_types:
|
|
185
|
+
if rel.source_type not in entity_names:
|
|
186
|
+
errors.append(
|
|
187
|
+
f"Relationship '{rel.name}' references unknown source type: {rel.source_type}"
|
|
188
|
+
)
|
|
189
|
+
if rel.target_type not in entity_names:
|
|
190
|
+
errors.append(
|
|
191
|
+
f"Relationship '{rel.name}' references unknown target type: {rel.target_type}"
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
# Check for duplicate entity names
|
|
195
|
+
seen_names = set()
|
|
196
|
+
for entity in self.entity_types:
|
|
197
|
+
if entity.name in seen_names:
|
|
198
|
+
errors.append(f"Duplicate entity type name: {entity.name}")
|
|
199
|
+
seen_names.add(entity.name)
|
|
200
|
+
|
|
201
|
+
return errors
|
|
202
|
+
|
|
203
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
204
|
+
"""Convert schema to dictionary for serialization."""
|
|
205
|
+
return {
|
|
206
|
+
"id": self.id,
|
|
207
|
+
"name": self.name,
|
|
208
|
+
"description": self.description,
|
|
209
|
+
"entity_types": [
|
|
210
|
+
{
|
|
211
|
+
"name": e.name,
|
|
212
|
+
"description": e.description,
|
|
213
|
+
"attributes": e.attributes,
|
|
214
|
+
}
|
|
215
|
+
for e in self.entity_types
|
|
216
|
+
],
|
|
217
|
+
"relationship_types": [
|
|
218
|
+
{
|
|
219
|
+
"name": r.name,
|
|
220
|
+
"description": r.description,
|
|
221
|
+
"source_type": r.source_type,
|
|
222
|
+
"target_type": r.target_type,
|
|
223
|
+
}
|
|
224
|
+
for r in self.relationship_types
|
|
225
|
+
],
|
|
226
|
+
"learning_categories": self.learning_categories,
|
|
227
|
+
"excluded_categories": self.excluded_categories,
|
|
228
|
+
"min_occurrences_for_heuristic": self.min_occurrences_for_heuristic,
|
|
229
|
+
"confidence_decay_days": self.confidence_decay_days,
|
|
230
|
+
"created_at": self.created_at.isoformat(),
|
|
231
|
+
"updated_at": self.updated_at.isoformat(),
|
|
232
|
+
"metadata": self.metadata,
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
@classmethod
|
|
236
|
+
def from_dict(cls, data: Dict[str, Any]) -> "DomainSchema":
|
|
237
|
+
"""Create schema from dictionary."""
|
|
238
|
+
entity_types = [
|
|
239
|
+
EntityType(
|
|
240
|
+
name=e["name"],
|
|
241
|
+
description=e["description"],
|
|
242
|
+
attributes=e.get("attributes", []),
|
|
243
|
+
)
|
|
244
|
+
for e in data.get("entity_types", [])
|
|
245
|
+
]
|
|
246
|
+
|
|
247
|
+
relationship_types = [
|
|
248
|
+
RelationshipType(
|
|
249
|
+
name=r["name"],
|
|
250
|
+
description=r["description"],
|
|
251
|
+
source_type=r["source_type"],
|
|
252
|
+
target_type=r["target_type"],
|
|
253
|
+
)
|
|
254
|
+
for r in data.get("relationship_types", [])
|
|
255
|
+
]
|
|
256
|
+
|
|
257
|
+
return cls(
|
|
258
|
+
id=data.get("id", str(uuid.uuid4())),
|
|
259
|
+
name=data["name"],
|
|
260
|
+
description=data["description"],
|
|
261
|
+
entity_types=entity_types,
|
|
262
|
+
relationship_types=relationship_types,
|
|
263
|
+
learning_categories=data.get("learning_categories", []),
|
|
264
|
+
excluded_categories=data.get("excluded_categories", []),
|
|
265
|
+
min_occurrences_for_heuristic=data.get("min_occurrences_for_heuristic", 3),
|
|
266
|
+
confidence_decay_days=data.get("confidence_decay_days", 30.0),
|
|
267
|
+
metadata=data.get("metadata", {}),
|
|
268
|
+
)
|