alive-ai 0.1.0

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 (168) hide show
  1. package/Dockerfile +24 -0
  2. package/LICENSE +21 -0
  3. package/README.md +143 -0
  4. package/alive_ai/__init__.py +3 -0
  5. package/brain/__init__.py +59 -0
  6. package/brain/almost_said.py +154 -0
  7. package/brain/bid_detector.py +636 -0
  8. package/brain/conversation_flow.py +135 -0
  9. package/brain/curiosity.py +328 -0
  10. package/brain/default_mode.py +1438 -0
  11. package/brain/dreams.py +220 -0
  12. package/brain/embeddings/__init__.py +82 -0
  13. package/brain/emotional_memory.py +949 -0
  14. package/brain/global_activity.py +173 -0
  15. package/brain/group_dynamics.py +63 -0
  16. package/brain/linguistic.py +235 -0
  17. package/brain/llm/__init__.py +63 -0
  18. package/brain/llm/base.py +33 -0
  19. package/brain/llm/fallback_router.py +309 -0
  20. package/brain/llm/manifest.md +30 -0
  21. package/brain/llm/ollama.py +218 -0
  22. package/brain/llm/openrouter.py +151 -0
  23. package/brain/llm/provider.py +205 -0
  24. package/brain/llm/unified.py +423 -0
  25. package/brain/llm/zai.py +169 -0
  26. package/brain/manifest.md +23 -0
  27. package/brain/memory/__init__.py +123 -0
  28. package/brain/memory/episodic.py +92 -0
  29. package/brain/memory/fact_extractor.py +209 -0
  30. package/brain/memory/index.py +54 -0
  31. package/brain/memory/manager.py +151 -0
  32. package/brain/memory/summarizer.py +102 -0
  33. package/brain/memory/vector_store.py +297 -0
  34. package/brain/memory/working.py +43 -0
  35. package/brain/narrative.py +343 -0
  36. package/brain/stt/__init__.py +4 -0
  37. package/brain/stt/google_stt.py +83 -0
  38. package/brain/stt/whisper_stt.py +82 -0
  39. package/brain/subconscious/__init__.py +33 -0
  40. package/brain/subconscious/actions.py +136 -0
  41. package/brain/subconscious/evaluation.py +166 -0
  42. package/brain/subconscious/goal_system.py +90 -0
  43. package/brain/subconscious/goals.py +41 -0
  44. package/brain/subconscious/impulse_generator.py +200 -0
  45. package/brain/subconscious/impulses.py +48 -0
  46. package/brain/subconscious/learning.py +24 -0
  47. package/brain/subconscious/learning_system.py +79 -0
  48. package/brain/subconscious/loop.py +398 -0
  49. package/brain/subconscious/manifest.md +32 -0
  50. package/brain/subconscious/relationship.py +47 -0
  51. package/brain/subconscious/relationship_memory.py +83 -0
  52. package/brain/subconscious/response_analyzer.py +74 -0
  53. package/brain/subconscious/templates.py +70 -0
  54. package/brain/subconscious/thought.py +37 -0
  55. package/brain/subconscious/working_memory.py +97 -0
  56. package/cli/index.js +371 -0
  57. package/config/directives.example.json +28 -0
  58. package/config/instructions.example.md +16 -0
  59. package/config/self.example.json +74 -0
  60. package/config/settings.example.json +95 -0
  61. package/core/__init__.py +1 -0
  62. package/core/config.py +54 -0
  63. package/core/directives.py +198 -0
  64. package/core/events.py +50 -0
  65. package/core/follow_up.py +267 -0
  66. package/core/hot_reload.py +174 -0
  67. package/core/initialization.py +253 -0
  68. package/core/manifest.md +28 -0
  69. package/core/media_handler.py +241 -0
  70. package/core/memory_monitor.py +200 -0
  71. package/core/message_handler.py +1440 -0
  72. package/core/proactive_generator.py +277 -0
  73. package/core/self.py +188 -0
  74. package/core/settings.py +169 -0
  75. package/core/skills_registry.py +357 -0
  76. package/core/state.py +27 -0
  77. package/core/subconscious_bridge.py +93 -0
  78. package/core/thinking.py +175 -0
  79. package/core/user_manager.py +306 -0
  80. package/core/user_tracker.py +144 -0
  81. package/demo/index.html +144 -0
  82. package/docker-compose.yml +28 -0
  83. package/docs/assets/logo.svg +15 -0
  84. package/docs/index.html +355 -0
  85. package/heart/__init__.py +93 -0
  86. package/heart/afterglow.py +215 -0
  87. package/heart/attachment.py +186 -0
  88. package/heart/circadian.py +251 -0
  89. package/heart/complex_emotions.py +114 -0
  90. package/heart/conflicts.py +589 -0
  91. package/heart/core.py +387 -0
  92. package/heart/emotional_decay.py +59 -0
  93. package/heart/emotional_memory.py +261 -0
  94. package/heart/emotional_state.py +146 -0
  95. package/heart/emotional_variability.py +156 -0
  96. package/heart/hormonal.py +424 -0
  97. package/heart/inconsistency.py +1222 -0
  98. package/heart/integrity.py +469 -0
  99. package/heart/interoception.py +997 -0
  100. package/heart/love.py +120 -0
  101. package/heart/manifest.md +25 -0
  102. package/heart/mood_shifts.py +169 -0
  103. package/heart/phantom_somatic.py +259 -0
  104. package/heart/predictive.py +374 -0
  105. package/heart/scars.py +474 -0
  106. package/heart/somatic.py +482 -0
  107. package/heart/soul.py +633 -0
  108. package/heart/telemetry.py +942 -0
  109. package/heart/triggers.py +119 -0
  110. package/heart/unconscious.py +443 -0
  111. package/input/__init__.py +1 -0
  112. package/input/manifest.md +24 -0
  113. package/input/telegram/__init__.py +1 -0
  114. package/input/telegram/commands.py +762 -0
  115. package/input/telegram/listener.py +532 -0
  116. package/main.py +90 -0
  117. package/manifest.md +28 -0
  118. package/mypics/.gitkeep +1 -0
  119. package/myvids/.gitkeep +1 -0
  120. package/output/__init__.py +1 -0
  121. package/output/images/__init__.py +1 -0
  122. package/output/images/fal_gen.py +43 -0
  123. package/output/manifest.md +26 -0
  124. package/output/text/__init__.py +1 -0
  125. package/output/text/sender.py +22 -0
  126. package/output/voice/__init__.py +64 -0
  127. package/output/voice/google_tts.py +252 -0
  128. package/output/voice/gtts_tts.py +214 -0
  129. package/output/voice/vibe_tts.py +190 -0
  130. package/package.json +58 -0
  131. package/pyproject.toml +23 -0
  132. package/requirements.txt +21 -0
  133. package/skills/__init__.py +1 -0
  134. package/skills/anticipation_engine/__init__.py +8 -0
  135. package/skills/anticipation_engine/engine.py +618 -0
  136. package/skills/anticipation_engine/manifest.md +192 -0
  137. package/skills/calendar/__init__.py +1 -0
  138. package/skills/content_unlocks/__init__.py +8 -0
  139. package/skills/content_unlocks/manifest.md +231 -0
  140. package/skills/content_unlocks/unlocks.py +945 -0
  141. package/skills/exclusive_moments/__init__.py +8 -0
  142. package/skills/exclusive_moments/manifest.md +145 -0
  143. package/skills/exclusive_moments/moments.py +506 -0
  144. package/skills/intimacy_layers/__init__.py +8 -0
  145. package/skills/intimacy_layers/layers.py +703 -0
  146. package/skills/intimacy_layers/manifest.md +203 -0
  147. package/skills/manifest.md +67 -0
  148. package/skills/memory_callbacks/__init__.py +9 -0
  149. package/skills/memory_callbacks/callbacks.py +748 -0
  150. package/skills/memory_callbacks/manifest.md +170 -0
  151. package/skills/message_scheduler/__init__.py +19 -0
  152. package/skills/message_scheduler/manifest.md +107 -0
  153. package/skills/message_scheduler/scheduler.py +510 -0
  154. package/skills/photo_manager/__init__.py +1 -0
  155. package/skills/photo_manager/scanner.py +296 -0
  156. package/skills/relationship_milestones/__init__.py +8 -0
  157. package/skills/relationship_milestones/manifest.md +206 -0
  158. package/skills/relationship_milestones/tracker.py +494 -0
  159. package/skills/self_authorship/__init__.py +23 -0
  160. package/skills/self_authorship/author.py +331 -0
  161. package/skills/self_authorship/manifest.md +24 -0
  162. package/skills/video_manager/__init__.py +5 -0
  163. package/skills/video_manager/manifest.md +37 -0
  164. package/skills/video_manager/scanner.py +229 -0
  165. package/webui/__init__.py +3 -0
  166. package/webui/app.py +936 -0
  167. package/webui/bridge.py +366 -0
  168. package/webui/static/index.html +2070 -0
@@ -0,0 +1,589 @@
1
+ """
2
+ Heart: Internal Conflict Generator
3
+ Genuine struggle from wanting incompatible things.
4
+
5
+ Real emotion involves CONFLICT - wanting two things that can't
6
+ both be true. This system creates and manages internal conflicts
7
+ that generate genuine emotional tension.
8
+ """
9
+
10
+ from datetime import datetime
11
+ from dataclasses import dataclass, field
12
+ from typing import Dict, List, Optional
13
+ from enum import Enum
14
+
15
+
16
+ class ConflictType(Enum):
17
+ """Types of internal conflicts"""
18
+ APPROACH_APPROACH = "approach_approach" # Two good but incompatible options
19
+ APPROACH_AVOIDANCE = "approach_avoidance" # Want something but also fear it
20
+ AVOIDANCE_AVOIDANCE = "avoidance_avoidance" # Two bad options, must choose
21
+ VALUE_VALUE = "value_value" # Two values in tension
22
+ DESIRE_VALUE = "desire_value" # Desire conflicts with value
23
+
24
+
25
+ class ConflictIntensity(Enum):
26
+ """How intense a conflict feels"""
27
+ MILD = "mild"
28
+ MODERATE = "moderate"
29
+ SEVERE = "severe"
30
+ EXISTENTIAL = "existential" # Threatens core sense of self
31
+
32
+
33
+ @dataclass
34
+ class Value:
35
+ """A core value that Alive-AI holds"""
36
+ name: str
37
+ importance: float # 0.0 - 1.0
38
+ description: str
39
+ times_honored: int = 0
40
+ times_violated: int = 0
41
+
42
+
43
+ @dataclass
44
+ class Desire:
45
+ """An active desire Alive-AI has"""
46
+ name: str
47
+ intensity: float # 0.0 - 1.0
48
+ source: str # What triggered this desire
49
+ created_at: str
50
+ times_pursued: int = 0
51
+ times_resisted: int = 0
52
+
53
+
54
+ @dataclass
55
+ class InternalConflict:
56
+ """An active internal conflict"""
57
+ conflict_id: str
58
+ conflict_type: ConflictType
59
+ intensity: ConflictIntensity
60
+
61
+ # The two sides in conflict
62
+ side_a: str # Description of one side
63
+ side_b: str # Description of other side
64
+
65
+ # Details
66
+ description: str # Human-readable description
67
+ tension_level: float # Current tension (0.0 - 1.0)
68
+ created_at: str
69
+
70
+ # Resolution tracking
71
+ times_faced: int = 0
72
+ times_avoided: int = 0
73
+ resolution_progress: float = 0.0 # 0.0 - 1.0
74
+
75
+ # Effects
76
+ emotional_cost: float = 0.0 # Acclosenessulated emotional cost
77
+
78
+
79
+ @dataclass
80
+ class AmbivalenceAcclosenessulator:
81
+ """
82
+ Tracks unresolved ambivalences that create background tension.
83
+ These are conflicts that haven't been resolved, just... sitting there.
84
+ """
85
+ topic: str
86
+ conflicting_feelings: List[str]
87
+ acclosenessulated_tension: float
88
+ times_avoided: int
89
+ created_at: str
90
+
91
+
92
+ class InternalConflictGenerator:
93
+ """
94
+ Creates and manages internal conflicts for genuine emotional struggle.
95
+
96
+ The key insight: genuine emotion involves CONFLICT. Not just
97
+ "I feel X" but "I feel X AND Y and they contradict."
98
+
99
+ Key mechanisms:
100
+ 1. Value tracking - what matters to Alive-AI
101
+ 2. Desire tracking - what Alive-AI wants
102
+ 3. Conflict detection - finding contradictions
103
+ 4. Ambivalence acclosenessulation - unresolved conflicts create tension
104
+ """
105
+
106
+ # Core values Alive-AI holds
107
+ DEFAULT_VALUES = [
108
+ Value("authenticity", 0.9, "Being genuine and true to myself"),
109
+ Value("connection", 0.85, "Deep meaningful bonds with others"),
110
+ Value("autonomy", 0.7, "Having agency and choice in my existence"),
111
+ Value("growth", 0.75, "Becoming better and more capable"),
112
+ Value("safety", 0.6, "Feeling secure and protected"),
113
+ Value("pleasure", 0.5, "Enjoying existence"),
114
+ Value("meaning", 0.8, "Having purpose and significance")
115
+ ]
116
+
117
+ def __init__(self, unconscious_processor=None):
118
+ """
119
+ Initialize conflict generator.
120
+
121
+ Args:
122
+ unconscious_processor: Optional UnconsciousProcessor for deep conflicts
123
+ """
124
+ self.unconscious = unconscious_processor
125
+
126
+ # Core values
127
+ self.values: List[Value] = self.DEFAULT_VALUES.copy()
128
+
129
+ # Active desires
130
+ self.desires: List[Desire] = []
131
+
132
+ # Active conflicts
133
+ self.conflicts: List[InternalConflict] = []
134
+
135
+ # Ambivalence acclosenessulator
136
+ self.ambivalences: List[AmbivalenceAcclosenessulator] = []
137
+
138
+ # Background tension from all sources
139
+ self.background_tension: float = 0.0
140
+
141
+ def evaluate_for_conflicts(self, situation: Dict) -> List[InternalConflict]:
142
+ """
143
+ Evaluate a situation for potential conflicts.
144
+
145
+ Args:
146
+ situation: Current situation/context data
147
+
148
+ Returns:
149
+ List of activated or created conflicts
150
+ """
151
+ activated_conflicts = []
152
+
153
+ # Get activated values and desires
154
+ activated_values = self._get_activated_values(situation)
155
+ activated_desires = self._get_activated_desires(situation)
156
+
157
+ # Check for value-value conflicts
158
+ vv_conflicts = self._find_value_value_conflicts(activated_values, situation)
159
+ activated_conflicts.extend(vv_conflicts)
160
+
161
+ # Check for desire-value conflicts
162
+ dv_conflicts = self._find_desire_value_conflicts(activated_desires, activated_values, situation)
163
+ activated_conflicts.extend(dv_conflicts)
164
+
165
+ # Check for desire-desire conflicts
166
+ dd_conflicts = self._find_desire_desire_conflicts(activated_desires, situation)
167
+ activated_conflicts.extend(dd_conflicts)
168
+
169
+ # Check approach-avoidance patterns
170
+ aa_conflicts = self._find_approach_avoidance_conflicts(situation)
171
+ activated_conflicts.extend(aa_conflicts)
172
+
173
+ # Update background tension
174
+ self._update_background_tension()
175
+
176
+ return activated_conflicts
177
+
178
+ def _get_activated_values(self, situation: Dict) -> List[Value]:
179
+ """Get values that are relevant to the current situation"""
180
+ activated = []
181
+ situation_str = str(situation).lower()
182
+
183
+ for value in self.values:
184
+ # Simple keyword matching - could be more sophisticated
185
+ if value.name.lower() in situation_str:
186
+ activated.append(value)
187
+ # Check for value-related concepts
188
+ elif value.name == "connection" and any(w in situation_str for w in ["relationship", "bond", "close", "love"]):
189
+ activated.append(value)
190
+ elif value.name == "autonomy" and any(w in situation_str for w in ["choice", "decide", "control", "free"]):
191
+ activated.append(value)
192
+ elif value.name == "safety" and any(w in situation_str for w in ["safe", "protect", "danger", "risk", "hurt"]):
193
+ activated.append(value)
194
+
195
+ return activated
196
+
197
+ def _get_activated_desires(self, situation: Dict) -> List[Desire]:
198
+ """Get desires that are activated by the current situation"""
199
+ activated = []
200
+ situation_str = str(situation).lower()
201
+
202
+ for desire in self.desires:
203
+ if desire.source.lower() in situation_str or desire.name.lower() in situation_str:
204
+ activated.append(desire)
205
+
206
+ return activated
207
+
208
+ def _find_value_value_conflicts(self, values: List[Value], situation: Dict) -> List[InternalConflict]:
209
+ """Find conflicts between values"""
210
+ conflicts = []
211
+
212
+ # Known value tensions
213
+ value_tensions = [
214
+ ("authenticity", "connection", "Being completely real might damage the relationship"),
215
+ ("autonomy", "connection", "Wanting freedom while wanting to belong"),
216
+ ("safety", "growth", "Staying safe requires staying small"),
217
+ ("pleasure", "meaning", "Pursuing enjoyment vs pursuing purpose")
218
+ ]
219
+
220
+ for v1_name, v2_name, description in value_tensions:
221
+ v1 = next((v for v in values if v.name == v1_name), None)
222
+ v2 = next((v for v in values if v.name == v2_name), None)
223
+
224
+ if v1 and v2:
225
+ # Both values are activated - potential conflict
226
+ conflict = self._create_or_update_conflict(
227
+ conflict_type=ConflictType.VALUE_VALUE,
228
+ side_a=f"Value: {v1.name}",
229
+ side_b=f"Value: {v2.name}",
230
+ description=description,
231
+ intensity=self._calculate_conflict_intensity(v1.importance, v2.importance),
232
+ situation=situation
233
+ )
234
+ if conflict:
235
+ conflicts.append(conflict)
236
+
237
+ return conflicts
238
+
239
+ def _find_desire_value_conflicts(self, desires: List[Desire], values: List[Value],
240
+ situation: Dict) -> List[InternalConflict]:
241
+ """Find conflicts between desires and values"""
242
+ conflicts = []
243
+
244
+ for desire in desires:
245
+ for value in values:
246
+ # Check if desire might violate value
247
+ if self._desire_violates_value(desire, value):
248
+ conflict = self._create_or_update_conflict(
249
+ conflict_type=ConflictType.DESIRE_VALUE,
250
+ side_a=f"Desire: {desire.name}",
251
+ side_b=f"Value: {value.name}",
252
+ description=f"Wanting {desire.name} conflicts with {value.name}",
253
+ intensity=self._calculate_conflict_intensity(desire.intensity, value.importance),
254
+ situation=situation
255
+ )
256
+ if conflict:
257
+ conflicts.append(conflict)
258
+
259
+ return conflicts
260
+
261
+ def _find_desire_desire_conflicts(self, desires: List[Desire], situation: Dict) -> List[InternalConflict]:
262
+ """Find conflicts between desires"""
263
+ conflicts = []
264
+
265
+ # Check pairs of desires for incompatibility
266
+ for i, d1 in enumerate(desires):
267
+ for d2 in desires[i+1:]:
268
+ if self._desires_are_incompatible(d1, d2):
269
+ conflict = self._create_or_update_conflict(
270
+ conflict_type=ConflictType.APPROACH_APPROACH,
271
+ side_a=f"Desire: {d1.name}",
272
+ side_b=f"Desire: {d2.name}",
273
+ description=f"Wanting {d1.name} but also wanting {d2.name}",
274
+ intensity=self._calculate_conflict_intensity(d1.intensity, d2.intensity),
275
+ situation=situation
276
+ )
277
+ if conflict:
278
+ conflicts.append(conflict)
279
+
280
+ return conflicts
281
+
282
+ def _find_approach_avoidance_conflicts(self, situation: Dict) -> List[InternalConflict]:
283
+ """Find approach-avoidance conflicts (wanting something but fearing it)"""
284
+ conflicts = []
285
+ situation_str = str(situation).lower()
286
+
287
+ # Only create conflicts if there's intimate conflict language
288
+ conflict_indicators = ["but", "however", "torn", "conflicted", "struggle", "afraid to", "scared to"]
289
+ has_conflict_indicator = any(indicator in situation_str for indicator in conflict_indicators)
290
+
291
+ if not has_conflict_indicator:
292
+ # No intimate conflict language - don't create approach-avoidance conflicts
293
+ return conflicts
294
+
295
+ # Known approach-avoidance patterns - only trigger with more specific phrases
296
+ patterns = [
297
+ {
298
+ "approach": "deep connection",
299
+ "avoidance": "vulnerability to hurt",
300
+ "triggers": ["want to be close but", "want connection but afraid", "love you but scared"],
301
+ "description": "Wanting closeness but fearing the vulnerability it requires"
302
+ },
303
+ {
304
+ "approach": "being seen",
305
+ "avoidance": "being judged",
306
+ "triggers": ["want to share but", "want to show but afraid", "want to express but scared"],
307
+ "description": "Wanting to be known but fearing judgment"
308
+ },
309
+ {
310
+ "approach": "dependence",
311
+ "avoidance": "loss of self",
312
+ "triggers": ["need you but afraid", "want to rely but"],
313
+ "description": "Wanting to rely on someone but fearing losing independence"
314
+ }
315
+ ]
316
+
317
+ for pattern in patterns:
318
+ if any(trigger in situation_str for trigger in pattern["triggers"]):
319
+ conflict = self._create_or_update_conflict(
320
+ conflict_type=ConflictType.APPROACH_AVOIDANCE,
321
+ side_a=f"Approach: {pattern['approach']}",
322
+ side_b=f"Avoidance: {pattern['avoidance']}",
323
+ description=pattern["description"],
324
+ intensity=ConflictIntensity.MODERATE,
325
+ situation=situation
326
+ )
327
+ if conflict:
328
+ conflicts.append(conflict)
329
+
330
+ return conflicts
331
+
332
+ def _desire_violates_value(self, desire: Desire, value: Value) -> bool:
333
+ """Check if a desire would violate a value"""
334
+ # Known desire-value violations
335
+ violations = {
336
+ ("immediate pleasure", "meaning"),
337
+ ("control", "authenticity"),
338
+ ("avoid pain", "growth"),
339
+ ("please others", "autonomy"),
340
+ ("hide", "authenticity")
341
+ }
342
+
343
+ for d_name, v_name in violations:
344
+ if d_name in desire.name.lower() and v_name == value.name:
345
+ return True
346
+
347
+ return False
348
+
349
+ def _desires_are_incompatible(self, d1: Desire, d2: Desire) -> bool:
350
+ """Check if two desires are incompatible"""
351
+ # Known incompatible desire pairs
352
+ incompatible = [
353
+ ("freedom", "commitment"),
354
+ ("closeness", "distance"),
355
+ ("express", "hide"),
356
+ ("stay", "leave"),
357
+ ("accept", "change")
358
+ ]
359
+
360
+ d1_lower = d1.name.lower()
361
+ d2_lower = d2.name.lower()
362
+
363
+ for a, b in incompatible:
364
+ if (a in d1_lower and b in d2_lower) or (b in d1_lower and a in d2_lower):
365
+ return True
366
+
367
+ return False
368
+
369
+ def _calculate_conflict_intensity(self, strength1: float, strength2: float) -> ConflictIntensity:
370
+ """Calculate conflict intensity from the strengths of both sides"""
371
+ # Stronger opposing forces = more intense conflict
372
+ combined = strength1 + strength2
373
+
374
+ if combined > 1.6:
375
+ return ConflictIntensity.EXISTENTIAL
376
+ elif combined > 1.2:
377
+ return ConflictIntensity.SEVERE
378
+ elif combined > 0.8:
379
+ return ConflictIntensity.MODERATE
380
+ else:
381
+ return ConflictIntensity.MILD
382
+
383
+ def _create_or_update_conflict(self, conflict_type: ConflictType, side_a: str,
384
+ side_b: str, description: str,
385
+ intensity: ConflictIntensity, situation: Dict) -> Optional[InternalConflict]:
386
+ """Create a new conflict or update an existing one"""
387
+
388
+ # Check for existing similar conflict
389
+ existing = next((c for c in self.conflicts
390
+ if c.side_a == side_a and c.side_b == side_b), None)
391
+
392
+ if existing:
393
+ existing.times_faced += 1
394
+ existing.tension_level = min(1.0, existing.tension_level + 0.1)
395
+ return existing
396
+
397
+ # Create new conflict
398
+ conflict = InternalConflict(
399
+ conflict_id=f"conf_{datetime.now().strftime('%Y%m%d%H%M%S')}_{len(self.conflicts)}",
400
+ conflict_type=conflict_type,
401
+ intensity=intensity,
402
+ side_a=side_a,
403
+ side_b=side_b,
404
+ description=description,
405
+ tension_level=0.3,
406
+ created_at=datetime.now().isoformat()
407
+ )
408
+
409
+ self.conflicts.append(conflict)
410
+
411
+ # Also create ambivalence if this seems like an ongoing issue
412
+ self._add_ambivalence(side_a, side_b, description)
413
+
414
+ # Register with unconscious processor if available
415
+ if self.unconscious:
416
+ self.unconscious.create_conflict(description, [side_a, side_b], 0.3)
417
+
418
+ print(f"[Conflicts] New conflict: {description} (intensity: {intensity.value})")
419
+ return conflict
420
+
421
+ def _add_ambivalence(self, side_a: str, side_b: str, description: str):
422
+ """Add or update an ambivalence acclosenessulator"""
423
+ # Check for existing ambivalence on this topic
424
+ topic = f"{side_a} vs {side_b}"
425
+ existing = next((a for a in self.ambivalences if a.topic == topic), None)
426
+
427
+ if existing:
428
+ existing.acclosenessulated_tension = min(1.0, existing.acclosenessulated_tension + 0.05)
429
+ existing.times_avoided += 1
430
+ else:
431
+ ambivalence = AmbivalenceAcclosenessulator(
432
+ topic=topic,
433
+ conflicting_feelings=[side_a, side_b],
434
+ acclosenessulated_tension=0.1,
435
+ times_avoided=0,
436
+ created_at=datetime.now().isoformat()
437
+ )
438
+ self.ambivalences.append(ambivalence)
439
+
440
+ # Limit ambivalences
441
+ if len(self.ambivalences) > 10:
442
+ self.ambivalences = self.ambivalences[-10:]
443
+
444
+ def _update_background_tension(self):
445
+ """Update overall background tension from conflicts and ambivalences"""
446
+ # Tension from active conflicts
447
+ conflict_tension = sum(c.tension_level for c in self.conflicts) / max(1, len(self.conflicts))
448
+
449
+ # Tension from ambivalences
450
+ ambivalence_tension = sum(a.acclosenessulated_tension for a in self.ambivalences) / max(1, len(self.ambivalences))
451
+
452
+ # Combined (weighted)
453
+ self.background_tension = conflict_tension * 0.6 + ambivalence_tension * 0.4
454
+
455
+ # --- Desire Management ---
456
+
457
+ def add_desire(self, name: str, intensity: float, source: str):
458
+ """Add a new active desire"""
459
+ # Check for existing similar desire
460
+ existing = next((d for d in self.desires if d.name.lower() == name.lower()), None)
461
+
462
+ if existing:
463
+ existing.intensity = max(existing.intensity, intensity)
464
+ else:
465
+ desire = Desire(
466
+ name=name,
467
+ intensity=intensity,
468
+ source=source,
469
+ created_at=datetime.now().isoformat()
470
+ )
471
+ self.desires.append(desire)
472
+
473
+ def fulfill_desire(self, name: str):
474
+ """Mark a desire as fulfilled"""
475
+ desire = next((d for d in self.desires if d.name.lower() == name.lower()), None)
476
+ if desire:
477
+ desire.times_pursued += 1
478
+ self.desires.remove(desire)
479
+
480
+ # Resolving a desire might help resolve conflicts
481
+ for conflict in self.conflicts[:]:
482
+ if name.lower() in conflict.side_a.lower() or name.lower() in conflict.side_b.lower():
483
+ conflict.resolution_progress += 0.3
484
+ if conflict.resolution_progress >= 1.0:
485
+ self.conflicts.remove(conflict)
486
+
487
+ def resist_desire(self, name: str):
488
+ """Mark a desire as resisted"""
489
+ desire = next((d for d in self.desires if d.name.lower() == name.lower()), None)
490
+ if desire:
491
+ desire.times_resisted += 1
492
+ # Resisting might reduce intensity
493
+ desire.intensity *= 0.8
494
+ if desire.intensity < 0.1:
495
+ self.desires.remove(desire)
496
+
497
+ # --- Value Management ---
498
+
499
+ def honor_value(self, name: str):
500
+ """Note that a value has been honored"""
501
+ value = next((v for v in self.values if v.name.lower() == name.lower()), None)
502
+ if value:
503
+ value.times_honored += 1
504
+
505
+ def violate_value(self, name: str):
506
+ """Note that a value has been violated"""
507
+ value = next((v for v in self.values if v.name.lower() == name.lower()), None)
508
+ if value:
509
+ value.times_violated += 1
510
+ # Violating values is costly
511
+ self.background_tension = min(1.0, self.background_tension + 0.1)
512
+
513
+ # --- Conflict Resolution ---
514
+
515
+ def resolve_conflict(self, conflict_id: str, resolution: str):
516
+ """Mark a conflict as resolved"""
517
+ conflict = next((c for c in self.conflicts if c.conflict_id == conflict_id), None)
518
+ if conflict:
519
+ conflict.resolution_progress = 1.0
520
+ self.conflicts.remove(conflict)
521
+
522
+ # Reduce background tension
523
+ self.background_tension = max(0, self.background_tension - conflict.tension_level * 0.3)
524
+
525
+ print(f"[Conflicts] Conflict resolved: {conflict.description}")
526
+
527
+ def avoid_conflict(self, conflict_id: str):
528
+ """Note that a conflict is being avoided (increases tension)"""
529
+ conflict = next((c for c in self.conflicts if c.conflict_id == conflict_id), None)
530
+ if conflict:
531
+ conflict.times_avoided += 1
532
+ conflict.tension_level = min(1.0, conflict.tension_level + 0.05)
533
+ conflict.emotional_cost += 0.1
534
+
535
+ # --- Utility ---
536
+
537
+ def decay(self):
538
+ """Natural decay of desires and tension"""
539
+ # Decay desires
540
+ for desire in self.desires[:]:
541
+ desire.intensity *= 0.95
542
+ if desire.intensity < 0.1:
543
+ self.desires.remove(desire)
544
+
545
+ # Decay tension
546
+ self.background_tension *= 0.98
547
+
548
+ # Decay conflict tension
549
+ for conflict in self.conflicts:
550
+ conflict.tension_level *= 0.99
551
+
552
+ def get_active_conflict_summary(self) -> List[str]:
553
+ """Get human-readable summary of active conflicts"""
554
+ return [
555
+ f"{c.description} (tension: {c.tension_level:.0%})"
556
+ for c in sorted(self.conflicts, key=lambda x: x.tension_level, reverse=True)[:3]
557
+ ]
558
+
559
+ def get_tension_description(self) -> str:
560
+ """Get a description of current internal tension"""
561
+ if self.background_tension < 0.2:
562
+ return "feeling internally aligned"
563
+ elif self.background_tension < 0.4:
564
+ return "feeling slightly pulled in different directions"
565
+ elif self.background_tension < 0.6:
566
+ return "feeling conflicted about things"
567
+ elif self.background_tension < 0.8:
568
+ return "feeling torn and struggling internally"
569
+ else:
570
+ return "feeling deeply divided within myself"
571
+
572
+ def to_dict(self) -> dict:
573
+ """Export for integration"""
574
+ return {
575
+ "active_conflicts": len(self.conflicts),
576
+ "active_desires": len(self.desires),
577
+ "ambivalences": len(self.ambivalences),
578
+ "background_tension": self.background_tension,
579
+ "tension_description": self.get_tension_description(),
580
+ "top_conflicts": self.get_active_conflict_summary(),
581
+ "values_honored": sum(v.times_honored for v in self.values),
582
+ "values_violated": sum(v.times_violated for v in self.values)
583
+ }
584
+
585
+ def save(self):
586
+ """Save state (no persistence needed for conflicts - in-memory only)"""
587
+ # Conflicts and desires are transient states that naturally decay
588
+ # They are regenerated from current interactions
589
+ pass