memorygraphMCP 0.11.7__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.
Files changed (65) hide show
  1. memorygraph/__init__.py +50 -0
  2. memorygraph/__main__.py +12 -0
  3. memorygraph/advanced_tools.py +509 -0
  4. memorygraph/analytics/__init__.py +46 -0
  5. memorygraph/analytics/advanced_queries.py +727 -0
  6. memorygraph/backends/__init__.py +21 -0
  7. memorygraph/backends/base.py +179 -0
  8. memorygraph/backends/cloud.py +75 -0
  9. memorygraph/backends/cloud_backend.py +858 -0
  10. memorygraph/backends/factory.py +577 -0
  11. memorygraph/backends/falkordb_backend.py +749 -0
  12. memorygraph/backends/falkordblite_backend.py +746 -0
  13. memorygraph/backends/ladybugdb_backend.py +242 -0
  14. memorygraph/backends/memgraph_backend.py +327 -0
  15. memorygraph/backends/neo4j_backend.py +298 -0
  16. memorygraph/backends/sqlite_fallback.py +463 -0
  17. memorygraph/backends/turso.py +448 -0
  18. memorygraph/cli.py +743 -0
  19. memorygraph/cloud_database.py +297 -0
  20. memorygraph/config.py +295 -0
  21. memorygraph/database.py +933 -0
  22. memorygraph/graph_analytics.py +631 -0
  23. memorygraph/integration/__init__.py +69 -0
  24. memorygraph/integration/context_capture.py +426 -0
  25. memorygraph/integration/project_analysis.py +583 -0
  26. memorygraph/integration/workflow_tracking.py +492 -0
  27. memorygraph/intelligence/__init__.py +59 -0
  28. memorygraph/intelligence/context_retrieval.py +447 -0
  29. memorygraph/intelligence/entity_extraction.py +386 -0
  30. memorygraph/intelligence/pattern_recognition.py +420 -0
  31. memorygraph/intelligence/temporal.py +374 -0
  32. memorygraph/migration/__init__.py +27 -0
  33. memorygraph/migration/manager.py +579 -0
  34. memorygraph/migration/models.py +142 -0
  35. memorygraph/migration/scripts/__init__.py +17 -0
  36. memorygraph/migration/scripts/bitemporal_migration.py +595 -0
  37. memorygraph/migration/scripts/multitenancy_migration.py +452 -0
  38. memorygraph/migration_tools_module.py +146 -0
  39. memorygraph/models.py +684 -0
  40. memorygraph/proactive/__init__.py +46 -0
  41. memorygraph/proactive/outcome_learning.py +444 -0
  42. memorygraph/proactive/predictive.py +410 -0
  43. memorygraph/proactive/session_briefing.py +399 -0
  44. memorygraph/relationships.py +668 -0
  45. memorygraph/server.py +883 -0
  46. memorygraph/sqlite_database.py +1876 -0
  47. memorygraph/tools/__init__.py +59 -0
  48. memorygraph/tools/activity_tools.py +262 -0
  49. memorygraph/tools/memory_tools.py +315 -0
  50. memorygraph/tools/migration_tools.py +181 -0
  51. memorygraph/tools/relationship_tools.py +147 -0
  52. memorygraph/tools/search_tools.py +406 -0
  53. memorygraph/tools/temporal_tools.py +339 -0
  54. memorygraph/utils/__init__.py +10 -0
  55. memorygraph/utils/context_extractor.py +429 -0
  56. memorygraph/utils/error_handling.py +151 -0
  57. memorygraph/utils/export_import.py +425 -0
  58. memorygraph/utils/graph_algorithms.py +200 -0
  59. memorygraph/utils/pagination.py +149 -0
  60. memorygraph/utils/project_detection.py +133 -0
  61. memorygraphmcp-0.11.7.dist-info/METADATA +970 -0
  62. memorygraphmcp-0.11.7.dist-info/RECORD +65 -0
  63. memorygraphmcp-0.11.7.dist-info/WHEEL +4 -0
  64. memorygraphmcp-0.11.7.dist-info/entry_points.txt +2 -0
  65. memorygraphmcp-0.11.7.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,668 @@
1
+ """
2
+ Advanced relationship management for Claude Code Memory Server.
3
+
4
+ This module implements the full 35-relationship type system with weighted
5
+ relationships, graph analytics, and intelligent relationship evolution.
6
+
7
+ Phase 4 Implementation - Advanced Relationship System
8
+ """
9
+
10
+ from enum import Enum
11
+ from typing import Dict, List, Optional, Tuple, Set, Any
12
+ from datetime import datetime, timedelta, timezone
13
+ from dataclasses import dataclass
14
+ import logging
15
+
16
+ from .models import (
17
+ RelationshipType,
18
+ RelationshipProperties,
19
+ Relationship,
20
+ Memory,
21
+ RelationshipError
22
+ )
23
+
24
+ logger = logging.getLogger(__name__)
25
+
26
+
27
+ class RelationshipCategory(str, Enum):
28
+ """
29
+ Categories that group related relationship types together.
30
+
31
+ Each category represents a different semantic dimension of how
32
+ memories can relate to each other.
33
+ """
34
+
35
+ CAUSAL = "causal" # Cause-and-effect relationships
36
+ SOLUTION = "solution" # Problem-solving relationships
37
+ CONTEXT = "context" # Environmental/situational relationships
38
+ LEARNING = "learning" # Knowledge building relationships
39
+ SIMILARITY = "similarity" # Similarity and analogy relationships
40
+ WORKFLOW = "workflow" # Sequential and dependency relationships
41
+ QUALITY = "quality" # Effectiveness and preference relationships
42
+
43
+
44
+ @dataclass
45
+ class RelationshipTypeMetadata:
46
+ """
47
+ Metadata describing a relationship type's characteristics.
48
+
49
+ Attributes:
50
+ category: The category this relationship belongs to
51
+ description: Human-readable description of the relationship
52
+ bidirectional: Whether the relationship implies a reverse relationship
53
+ default_strength: Default strength value (0.0 to 1.0)
54
+ default_confidence: Default confidence value (0.0 to 1.0)
55
+ inverse_type: The inverse relationship type (if bidirectional)
56
+ """
57
+
58
+ category: RelationshipCategory
59
+ description: str
60
+ bidirectional: bool = False
61
+ default_strength: float = 0.5
62
+ default_confidence: float = 0.8
63
+ inverse_type: Optional[RelationshipType] = None
64
+
65
+
66
+ # Complete metadata for all 35 relationship types
67
+ RELATIONSHIP_TYPE_METADATA: Dict[RelationshipType, RelationshipTypeMetadata] = {
68
+ # Causal relationships (5 types)
69
+ RelationshipType.CAUSES: RelationshipTypeMetadata(
70
+ category=RelationshipCategory.CAUSAL,
71
+ description="Memory A causes or directly triggers Memory B",
72
+ bidirectional=False,
73
+ default_strength=0.8,
74
+ default_confidence=0.7,
75
+ ),
76
+ RelationshipType.TRIGGERS: RelationshipTypeMetadata(
77
+ category=RelationshipCategory.CAUSAL,
78
+ description="Memory A initiates or activates Memory B",
79
+ bidirectional=False,
80
+ default_strength=0.7,
81
+ default_confidence=0.7,
82
+ ),
83
+ RelationshipType.LEADS_TO: RelationshipTypeMetadata(
84
+ category=RelationshipCategory.CAUSAL,
85
+ description="Memory A eventually results in Memory B",
86
+ bidirectional=False,
87
+ default_strength=0.6,
88
+ default_confidence=0.6,
89
+ ),
90
+ RelationshipType.PREVENTS: RelationshipTypeMetadata(
91
+ category=RelationshipCategory.CAUSAL,
92
+ description="Memory A prevents or blocks Memory B from occurring",
93
+ bidirectional=False,
94
+ default_strength=0.7,
95
+ default_confidence=0.7,
96
+ ),
97
+ RelationshipType.BREAKS: RelationshipTypeMetadata(
98
+ category=RelationshipCategory.CAUSAL,
99
+ description="Memory A breaks or disrupts Memory B",
100
+ bidirectional=False,
101
+ default_strength=0.8,
102
+ default_confidence=0.7,
103
+ ),
104
+
105
+ # Solution relationships (5 types)
106
+ RelationshipType.SOLVES: RelationshipTypeMetadata(
107
+ category=RelationshipCategory.SOLUTION,
108
+ description="Memory A solves the problem described in Memory B",
109
+ bidirectional=False,
110
+ default_strength=0.9,
111
+ default_confidence=0.8,
112
+ ),
113
+ RelationshipType.ADDRESSES: RelationshipTypeMetadata(
114
+ category=RelationshipCategory.SOLUTION,
115
+ description="Memory A addresses or partially solves Memory B",
116
+ bidirectional=False,
117
+ default_strength=0.7,
118
+ default_confidence=0.7,
119
+ ),
120
+ RelationshipType.ALTERNATIVE_TO: RelationshipTypeMetadata(
121
+ category=RelationshipCategory.SOLUTION,
122
+ description="Memory A is an alternative approach to Memory B",
123
+ bidirectional=True,
124
+ default_strength=0.6,
125
+ default_confidence=0.7,
126
+ inverse_type=RelationshipType.ALTERNATIVE_TO,
127
+ ),
128
+ RelationshipType.IMPROVES: RelationshipTypeMetadata(
129
+ category=RelationshipCategory.SOLUTION,
130
+ description="Memory A improves upon Memory B",
131
+ bidirectional=False,
132
+ default_strength=0.7,
133
+ default_confidence=0.7,
134
+ ),
135
+ RelationshipType.REPLACES: RelationshipTypeMetadata(
136
+ category=RelationshipCategory.SOLUTION,
137
+ description="Memory A replaces or supersedes Memory B",
138
+ bidirectional=False,
139
+ default_strength=0.8,
140
+ default_confidence=0.8,
141
+ ),
142
+
143
+ # Context relationships (5 types)
144
+ RelationshipType.OCCURS_IN: RelationshipTypeMetadata(
145
+ category=RelationshipCategory.CONTEXT,
146
+ description="Memory A occurs within the context of Memory B",
147
+ bidirectional=False,
148
+ default_strength=0.6,
149
+ default_confidence=0.8,
150
+ ),
151
+ RelationshipType.APPLIES_TO: RelationshipTypeMetadata(
152
+ category=RelationshipCategory.CONTEXT,
153
+ description="Memory A applies to or is relevant in Memory B context",
154
+ bidirectional=False,
155
+ default_strength=0.6,
156
+ default_confidence=0.7,
157
+ ),
158
+ RelationshipType.WORKS_WITH: RelationshipTypeMetadata(
159
+ category=RelationshipCategory.CONTEXT,
160
+ description="Memory A works together with Memory B",
161
+ bidirectional=True,
162
+ default_strength=0.7,
163
+ default_confidence=0.7,
164
+ inverse_type=RelationshipType.WORKS_WITH,
165
+ ),
166
+ RelationshipType.REQUIRES: RelationshipTypeMetadata(
167
+ category=RelationshipCategory.CONTEXT,
168
+ description="Memory A requires Memory B to function",
169
+ bidirectional=False,
170
+ default_strength=0.8,
171
+ default_confidence=0.8,
172
+ ),
173
+ RelationshipType.USED_IN: RelationshipTypeMetadata(
174
+ category=RelationshipCategory.CONTEXT,
175
+ description="Memory A is used within Memory B",
176
+ bidirectional=False,
177
+ default_strength=0.6,
178
+ default_confidence=0.7,
179
+ ),
180
+
181
+ # Learning relationships (5 types)
182
+ RelationshipType.BUILDS_ON: RelationshipTypeMetadata(
183
+ category=RelationshipCategory.LEARNING,
184
+ description="Memory A builds upon knowledge from Memory B",
185
+ bidirectional=False,
186
+ default_strength=0.7,
187
+ default_confidence=0.8,
188
+ ),
189
+ RelationshipType.CONTRADICTS: RelationshipTypeMetadata(
190
+ category=RelationshipCategory.LEARNING,
191
+ description="Memory A contradicts information in Memory B",
192
+ bidirectional=True,
193
+ default_strength=0.8,
194
+ default_confidence=0.6,
195
+ inverse_type=RelationshipType.CONTRADICTS,
196
+ ),
197
+ RelationshipType.CONFIRMS: RelationshipTypeMetadata(
198
+ category=RelationshipCategory.LEARNING,
199
+ description="Memory A confirms or validates Memory B",
200
+ bidirectional=False,
201
+ default_strength=0.7,
202
+ default_confidence=0.8,
203
+ ),
204
+ RelationshipType.GENERALIZES: RelationshipTypeMetadata(
205
+ category=RelationshipCategory.LEARNING,
206
+ description="Memory A is a generalization of Memory B",
207
+ bidirectional=False,
208
+ default_strength=0.6,
209
+ default_confidence=0.7,
210
+ inverse_type=RelationshipType.SPECIALIZES,
211
+ ),
212
+ RelationshipType.SPECIALIZES: RelationshipTypeMetadata(
213
+ category=RelationshipCategory.LEARNING,
214
+ description="Memory A is a specialization of Memory B",
215
+ bidirectional=False,
216
+ default_strength=0.6,
217
+ default_confidence=0.7,
218
+ inverse_type=RelationshipType.GENERALIZES,
219
+ ),
220
+
221
+ # Similarity relationships (5 types)
222
+ RelationshipType.SIMILAR_TO: RelationshipTypeMetadata(
223
+ category=RelationshipCategory.SIMILARITY,
224
+ description="Memory A is similar to Memory B",
225
+ bidirectional=True,
226
+ default_strength=0.6,
227
+ default_confidence=0.7,
228
+ inverse_type=RelationshipType.SIMILAR_TO,
229
+ ),
230
+ RelationshipType.VARIANT_OF: RelationshipTypeMetadata(
231
+ category=RelationshipCategory.SIMILARITY,
232
+ description="Memory A is a variant or version of Memory B",
233
+ bidirectional=False,
234
+ default_strength=0.7,
235
+ default_confidence=0.7,
236
+ ),
237
+ RelationshipType.RELATED_TO: RelationshipTypeMetadata(
238
+ category=RelationshipCategory.SIMILARITY,
239
+ description="Memory A is related to Memory B in some way",
240
+ bidirectional=True,
241
+ default_strength=0.5,
242
+ default_confidence=0.6,
243
+ inverse_type=RelationshipType.RELATED_TO,
244
+ ),
245
+ RelationshipType.ANALOGY_TO: RelationshipTypeMetadata(
246
+ category=RelationshipCategory.SIMILARITY,
247
+ description="Memory A serves as an analogy for Memory B",
248
+ bidirectional=False,
249
+ default_strength=0.5,
250
+ default_confidence=0.6,
251
+ ),
252
+ RelationshipType.OPPOSITE_OF: RelationshipTypeMetadata(
253
+ category=RelationshipCategory.SIMILARITY,
254
+ description="Memory A is the opposite or inverse of Memory B",
255
+ bidirectional=True,
256
+ default_strength=0.7,
257
+ default_confidence=0.7,
258
+ inverse_type=RelationshipType.OPPOSITE_OF,
259
+ ),
260
+
261
+ # Workflow relationships (5 types)
262
+ RelationshipType.FOLLOWS: RelationshipTypeMetadata(
263
+ category=RelationshipCategory.WORKFLOW,
264
+ description="Memory A follows Memory B in a sequence",
265
+ bidirectional=False,
266
+ default_strength=0.7,
267
+ default_confidence=0.8,
268
+ ),
269
+ RelationshipType.DEPENDS_ON: RelationshipTypeMetadata(
270
+ category=RelationshipCategory.WORKFLOW,
271
+ description="Memory A depends on Memory B being completed first",
272
+ bidirectional=False,
273
+ default_strength=0.8,
274
+ default_confidence=0.8,
275
+ ),
276
+ RelationshipType.ENABLES: RelationshipTypeMetadata(
277
+ category=RelationshipCategory.WORKFLOW,
278
+ description="Memory A enables or allows Memory B to occur",
279
+ bidirectional=False,
280
+ default_strength=0.7,
281
+ default_confidence=0.7,
282
+ ),
283
+ RelationshipType.BLOCKS: RelationshipTypeMetadata(
284
+ category=RelationshipCategory.WORKFLOW,
285
+ description="Memory A blocks or prevents Memory B from proceeding",
286
+ bidirectional=False,
287
+ default_strength=0.8,
288
+ default_confidence=0.7,
289
+ ),
290
+ RelationshipType.PARALLEL_TO: RelationshipTypeMetadata(
291
+ category=RelationshipCategory.WORKFLOW,
292
+ description="Memory A can occur in parallel with Memory B",
293
+ bidirectional=True,
294
+ default_strength=0.6,
295
+ default_confidence=0.7,
296
+ inverse_type=RelationshipType.PARALLEL_TO,
297
+ ),
298
+
299
+ # Quality relationships (5 types)
300
+ RelationshipType.EFFECTIVE_FOR: RelationshipTypeMetadata(
301
+ category=RelationshipCategory.QUALITY,
302
+ description="Memory A is effective for solving Memory B",
303
+ bidirectional=False,
304
+ default_strength=0.8,
305
+ default_confidence=0.7,
306
+ ),
307
+ RelationshipType.INEFFECTIVE_FOR: RelationshipTypeMetadata(
308
+ category=RelationshipCategory.QUALITY,
309
+ description="Memory A is ineffective for solving Memory B",
310
+ bidirectional=False,
311
+ default_strength=0.7,
312
+ default_confidence=0.7,
313
+ ),
314
+ RelationshipType.PREFERRED_OVER: RelationshipTypeMetadata(
315
+ category=RelationshipCategory.QUALITY,
316
+ description="Memory A is preferred over Memory B",
317
+ bidirectional=False,
318
+ default_strength=0.7,
319
+ default_confidence=0.7,
320
+ ),
321
+ RelationshipType.DEPRECATED_BY: RelationshipTypeMetadata(
322
+ category=RelationshipCategory.QUALITY,
323
+ description="Memory A is deprecated by Memory B",
324
+ bidirectional=False,
325
+ default_strength=0.8,
326
+ default_confidence=0.8,
327
+ inverse_type=RelationshipType.REPLACES,
328
+ ),
329
+ RelationshipType.VALIDATED_BY: RelationshipTypeMetadata(
330
+ category=RelationshipCategory.QUALITY,
331
+ description="Memory A is validated or proven by Memory B",
332
+ bidirectional=False,
333
+ default_strength=0.8,
334
+ default_confidence=0.8,
335
+ ),
336
+ }
337
+
338
+
339
+ class RelationshipManager:
340
+ """
341
+ Manages advanced relationship operations including creation,
342
+ validation, evolution, and graph analytics.
343
+
344
+ This class provides high-level relationship management on top of
345
+ the backend storage layer.
346
+ """
347
+
348
+ def __init__(self):
349
+ """Initialize the relationship manager."""
350
+ self.metadata = RELATIONSHIP_TYPE_METADATA
351
+
352
+ def get_relationship_metadata(
353
+ self,
354
+ relationship_type: RelationshipType
355
+ ) -> RelationshipTypeMetadata:
356
+ """
357
+ Get metadata for a relationship type.
358
+
359
+ Args:
360
+ relationship_type: The relationship type to look up
361
+
362
+ Returns:
363
+ Metadata for the relationship type
364
+
365
+ Raises:
366
+ ValueError: If relationship type is not recognized
367
+ """
368
+ if relationship_type not in self.metadata:
369
+ raise ValueError(f"Unknown relationship type: {relationship_type}")
370
+
371
+ return self.metadata[relationship_type]
372
+
373
+ def get_relationship_category(
374
+ self,
375
+ relationship_type: RelationshipType
376
+ ) -> RelationshipCategory:
377
+ """
378
+ Get the category for a relationship type.
379
+
380
+ Args:
381
+ relationship_type: The relationship type
382
+
383
+ Returns:
384
+ The category this relationship belongs to
385
+ """
386
+ metadata = self.get_relationship_metadata(relationship_type)
387
+ return metadata.category
388
+
389
+ def get_types_by_category(
390
+ self,
391
+ category: RelationshipCategory
392
+ ) -> List[RelationshipType]:
393
+ """
394
+ Get all relationship types in a category.
395
+
396
+ Args:
397
+ category: The relationship category
398
+
399
+ Returns:
400
+ List of relationship types in that category
401
+ """
402
+ return [
403
+ rel_type for rel_type, meta in self.metadata.items()
404
+ if meta.category == category
405
+ ]
406
+
407
+ def create_relationship_properties(
408
+ self,
409
+ relationship_type: RelationshipType,
410
+ strength: Optional[float] = None,
411
+ confidence: Optional[float] = None,
412
+ context: Optional[str] = None,
413
+ **kwargs
414
+ ) -> RelationshipProperties:
415
+ """
416
+ Create relationship properties with appropriate defaults.
417
+
418
+ Args:
419
+ relationship_type: The type of relationship
420
+ strength: Custom strength value (uses default if None)
421
+ confidence: Custom confidence value (uses default if None)
422
+ context: Optional context information
423
+ **kwargs: Additional property values
424
+
425
+ Returns:
426
+ RelationshipProperties instance with appropriate defaults
427
+ """
428
+ metadata = self.get_relationship_metadata(relationship_type)
429
+
430
+ return RelationshipProperties(
431
+ strength=strength if strength is not None else metadata.default_strength,
432
+ confidence=confidence if confidence is not None else metadata.default_confidence,
433
+ context=context,
434
+ **kwargs
435
+ )
436
+
437
+ def validate_relationship(
438
+ self,
439
+ from_memory_id: str,
440
+ to_memory_id: str,
441
+ relationship_type: RelationshipType
442
+ ) -> Tuple[bool, Optional[str]]:
443
+ """
444
+ Validate a relationship before creation.
445
+
446
+ Args:
447
+ from_memory_id: Source memory ID
448
+ to_memory_id: Target memory ID
449
+ relationship_type: Type of relationship
450
+
451
+ Returns:
452
+ Tuple of (is_valid, error_message)
453
+ """
454
+ # Check for self-relationships
455
+ if from_memory_id == to_memory_id:
456
+ return False, "Cannot create relationship from memory to itself"
457
+
458
+ # Validate relationship type exists
459
+ if relationship_type not in self.metadata:
460
+ return False, f"Unknown relationship type: {relationship_type}"
461
+
462
+ # All basic validations passed
463
+ return True, None
464
+
465
+ def should_create_inverse(
466
+ self,
467
+ relationship_type: RelationshipType
468
+ ) -> Tuple[bool, Optional[RelationshipType]]:
469
+ """
470
+ Check if an inverse relationship should be created.
471
+
472
+ Args:
473
+ relationship_type: The relationship type
474
+
475
+ Returns:
476
+ Tuple of (should_create, inverse_type)
477
+ """
478
+ metadata = self.get_relationship_metadata(relationship_type)
479
+
480
+ if metadata.bidirectional and metadata.inverse_type:
481
+ return True, metadata.inverse_type
482
+
483
+ return False, None
484
+
485
+ def calculate_relationship_strength(
486
+ self,
487
+ base_strength: float,
488
+ evidence_count: int,
489
+ success_rate: Optional[float] = None,
490
+ age_days: Optional[float] = None,
491
+ decay_rate: float = 0.01
492
+ ) -> float:
493
+ """
494
+ Calculate effective relationship strength considering multiple factors.
495
+
496
+ Args:
497
+ base_strength: Base strength value
498
+ evidence_count: Number of times relationship has been observed
499
+ success_rate: Success rate for solution relationships (0.0-1.0)
500
+ age_days: Age of relationship in days
501
+ decay_rate: Daily decay rate for strength
502
+
503
+ Returns:
504
+ Calculated effective strength (0.0-1.0)
505
+ """
506
+ strength = base_strength
507
+
508
+ # Boost based on evidence count (logarithmic)
509
+ if evidence_count > 1:
510
+ evidence_boost = min(0.2, 0.05 * (evidence_count - 1) ** 0.5)
511
+ strength = min(1.0, strength + evidence_boost)
512
+
513
+ # Adjust based on success rate
514
+ if success_rate is not None:
515
+ strength = strength * (0.5 + 0.5 * success_rate)
516
+
517
+ # Apply time-based decay
518
+ if age_days is not None and age_days > 0:
519
+ decay_factor = max(0.5, 1.0 - (decay_rate * age_days))
520
+ strength = strength * decay_factor
521
+
522
+ # Ensure within bounds
523
+ return max(0.0, min(1.0, strength))
524
+
525
+ def reinforce_relationship_properties(
526
+ self,
527
+ properties: RelationshipProperties,
528
+ success: bool = True,
529
+ strength_increase: float = 0.05,
530
+ confidence_increase: float = 0.03
531
+ ) -> RelationshipProperties:
532
+ """
533
+ Reinforce relationship properties based on successful use.
534
+
535
+ Args:
536
+ properties: Current relationship properties
537
+ success: Whether this reinforcement is from a success
538
+ strength_increase: How much to increase strength
539
+ confidence_increase: How much to increase confidence
540
+
541
+ Returns:
542
+ Updated relationship properties
543
+ """
544
+ new_evidence = properties.evidence_count + 1
545
+ new_validation = properties.validation_count + (1 if success else 0)
546
+ new_counter = properties.counter_evidence_count + (0 if success else 1)
547
+
548
+ # Calculate new success rate
549
+ total_evidence = new_validation + new_counter
550
+ new_success_rate = new_validation / total_evidence if total_evidence > 0 else None
551
+
552
+ # Adjust strength and confidence
553
+ if success:
554
+ new_strength = min(1.0, properties.strength + strength_increase)
555
+ new_confidence = min(1.0, properties.confidence + confidence_increase)
556
+ else:
557
+ new_strength = max(0.1, properties.strength - strength_increase * 0.5)
558
+ new_confidence = max(0.1, properties.confidence - confidence_increase * 0.5)
559
+
560
+ return RelationshipProperties(
561
+ strength=new_strength,
562
+ confidence=new_confidence,
563
+ context=properties.context,
564
+ evidence_count=new_evidence,
565
+ success_rate=new_success_rate,
566
+ created_at=properties.created_at,
567
+ last_validated=datetime.now(timezone.utc),
568
+ validation_count=new_validation,
569
+ counter_evidence_count=new_counter
570
+ )
571
+
572
+ def find_contradictory_relationships(
573
+ self,
574
+ relationships: List[Relationship]
575
+ ) -> List[Tuple[Relationship, Relationship]]:
576
+ """
577
+ Find pairs of relationships that may be contradictory.
578
+
579
+ Args:
580
+ relationships: List of relationships to analyze
581
+
582
+ Returns:
583
+ List of contradictory relationship pairs
584
+ """
585
+ contradictions = []
586
+
587
+ # Look for explicit contradictions
588
+ for i, rel1 in enumerate(relationships):
589
+ for rel2 in relationships[i+1:]:
590
+ # Same nodes, contradictory types
591
+ if (rel1.from_memory_id == rel2.from_memory_id and
592
+ rel1.to_memory_id == rel2.to_memory_id):
593
+
594
+ # Check for contradictory relationship types
595
+ contradictory_pairs = [
596
+ (RelationshipType.SOLVES, RelationshipType.INEFFECTIVE_FOR),
597
+ (RelationshipType.CONFIRMS, RelationshipType.CONTRADICTS),
598
+ (RelationshipType.EFFECTIVE_FOR, RelationshipType.INEFFECTIVE_FOR),
599
+ (RelationshipType.ENABLES, RelationshipType.BLOCKS),
600
+ (RelationshipType.PREVENTS, RelationshipType.CAUSES),
601
+ ]
602
+
603
+ for type_a, type_b in contradictory_pairs:
604
+ if ((rel1.type == type_a and rel2.type == type_b) or
605
+ (rel1.type == type_b and rel2.type == type_a)):
606
+ contradictions.append((rel1, rel2))
607
+
608
+ return contradictions
609
+
610
+ def suggest_relationship_type(
611
+ self,
612
+ from_memory: Memory,
613
+ to_memory: Memory,
614
+ context: Optional[str] = None
615
+ ) -> List[Tuple[RelationshipType, float]]:
616
+ """
617
+ Suggest appropriate relationship types based on memory types.
618
+
619
+ Args:
620
+ from_memory: Source memory
621
+ to_memory: Target memory
622
+ context: Optional context information
623
+
624
+ Returns:
625
+ List of (relationship_type, confidence) tuples, sorted by confidence
626
+ """
627
+ suggestions: List[Tuple[RelationshipType, float]] = []
628
+
629
+ # Problem -> Solution relationships
630
+ if from_memory.type.value == "solution" and to_memory.type.value == "problem":
631
+ suggestions.append((RelationshipType.SOLVES, 0.8))
632
+ suggestions.append((RelationshipType.ADDRESSES, 0.7))
633
+
634
+ # Error -> Fix relationships
635
+ if from_memory.type.value == "fix" and to_memory.type.value == "error":
636
+ suggestions.append((RelationshipType.SOLVES, 0.9))
637
+
638
+ # Technology relationships
639
+ if (from_memory.type.value == "technology" and
640
+ to_memory.type.value == "technology"):
641
+ suggestions.append((RelationshipType.WORKS_WITH, 0.6))
642
+ suggestions.append((RelationshipType.ALTERNATIVE_TO, 0.5))
643
+
644
+ # Workflow relationships
645
+ if from_memory.type.value == "task" and to_memory.type.value == "task":
646
+ suggestions.append((RelationshipType.FOLLOWS, 0.6))
647
+ suggestions.append((RelationshipType.DEPENDS_ON, 0.5))
648
+ suggestions.append((RelationshipType.PARALLEL_TO, 0.4))
649
+
650
+ # Code pattern relationships
651
+ if (from_memory.type.value == "code_pattern" and
652
+ to_memory.type.value == "code_pattern"):
653
+ suggestions.append((RelationshipType.SIMILAR_TO, 0.6))
654
+ suggestions.append((RelationshipType.VARIANT_OF, 0.5))
655
+ suggestions.append((RelationshipType.IMPROVES, 0.4))
656
+
657
+ # Default fallback
658
+ if not suggestions:
659
+ suggestions.append((RelationshipType.RELATED_TO, 0.5))
660
+
661
+ # Sort by confidence descending
662
+ suggestions.sort(key=lambda x: x[1], reverse=True)
663
+
664
+ return suggestions
665
+
666
+
667
+ # Singleton instance for easy access
668
+ relationship_manager = RelationshipManager()