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.
- package/Dockerfile +24 -0
- package/LICENSE +21 -0
- package/README.md +143 -0
- package/alive_ai/__init__.py +3 -0
- package/brain/__init__.py +59 -0
- package/brain/almost_said.py +154 -0
- package/brain/bid_detector.py +636 -0
- package/brain/conversation_flow.py +135 -0
- package/brain/curiosity.py +328 -0
- package/brain/default_mode.py +1438 -0
- package/brain/dreams.py +220 -0
- package/brain/embeddings/__init__.py +82 -0
- package/brain/emotional_memory.py +949 -0
- package/brain/global_activity.py +173 -0
- package/brain/group_dynamics.py +63 -0
- package/brain/linguistic.py +235 -0
- package/brain/llm/__init__.py +63 -0
- package/brain/llm/base.py +33 -0
- package/brain/llm/fallback_router.py +309 -0
- package/brain/llm/manifest.md +30 -0
- package/brain/llm/ollama.py +218 -0
- package/brain/llm/openrouter.py +151 -0
- package/brain/llm/provider.py +205 -0
- package/brain/llm/unified.py +423 -0
- package/brain/llm/zai.py +169 -0
- package/brain/manifest.md +23 -0
- package/brain/memory/__init__.py +123 -0
- package/brain/memory/episodic.py +92 -0
- package/brain/memory/fact_extractor.py +209 -0
- package/brain/memory/index.py +54 -0
- package/brain/memory/manager.py +151 -0
- package/brain/memory/summarizer.py +102 -0
- package/brain/memory/vector_store.py +297 -0
- package/brain/memory/working.py +43 -0
- package/brain/narrative.py +343 -0
- package/brain/stt/__init__.py +4 -0
- package/brain/stt/google_stt.py +83 -0
- package/brain/stt/whisper_stt.py +82 -0
- package/brain/subconscious/__init__.py +33 -0
- package/brain/subconscious/actions.py +136 -0
- package/brain/subconscious/evaluation.py +166 -0
- package/brain/subconscious/goal_system.py +90 -0
- package/brain/subconscious/goals.py +41 -0
- package/brain/subconscious/impulse_generator.py +200 -0
- package/brain/subconscious/impulses.py +48 -0
- package/brain/subconscious/learning.py +24 -0
- package/brain/subconscious/learning_system.py +79 -0
- package/brain/subconscious/loop.py +398 -0
- package/brain/subconscious/manifest.md +32 -0
- package/brain/subconscious/relationship.py +47 -0
- package/brain/subconscious/relationship_memory.py +83 -0
- package/brain/subconscious/response_analyzer.py +74 -0
- package/brain/subconscious/templates.py +70 -0
- package/brain/subconscious/thought.py +37 -0
- package/brain/subconscious/working_memory.py +97 -0
- package/cli/index.js +371 -0
- package/config/directives.example.json +28 -0
- package/config/instructions.example.md +16 -0
- package/config/self.example.json +74 -0
- package/config/settings.example.json +95 -0
- package/core/__init__.py +1 -0
- package/core/config.py +54 -0
- package/core/directives.py +198 -0
- package/core/events.py +50 -0
- package/core/follow_up.py +267 -0
- package/core/hot_reload.py +174 -0
- package/core/initialization.py +253 -0
- package/core/manifest.md +28 -0
- package/core/media_handler.py +241 -0
- package/core/memory_monitor.py +200 -0
- package/core/message_handler.py +1440 -0
- package/core/proactive_generator.py +277 -0
- package/core/self.py +188 -0
- package/core/settings.py +169 -0
- package/core/skills_registry.py +357 -0
- package/core/state.py +27 -0
- package/core/subconscious_bridge.py +93 -0
- package/core/thinking.py +175 -0
- package/core/user_manager.py +306 -0
- package/core/user_tracker.py +144 -0
- package/demo/index.html +144 -0
- package/docker-compose.yml +28 -0
- package/docs/assets/logo.svg +15 -0
- package/docs/index.html +355 -0
- package/heart/__init__.py +93 -0
- package/heart/afterglow.py +215 -0
- package/heart/attachment.py +186 -0
- package/heart/circadian.py +251 -0
- package/heart/complex_emotions.py +114 -0
- package/heart/conflicts.py +589 -0
- package/heart/core.py +387 -0
- package/heart/emotional_decay.py +59 -0
- package/heart/emotional_memory.py +261 -0
- package/heart/emotional_state.py +146 -0
- package/heart/emotional_variability.py +156 -0
- package/heart/hormonal.py +424 -0
- package/heart/inconsistency.py +1222 -0
- package/heart/integrity.py +469 -0
- package/heart/interoception.py +997 -0
- package/heart/love.py +120 -0
- package/heart/manifest.md +25 -0
- package/heart/mood_shifts.py +169 -0
- package/heart/phantom_somatic.py +259 -0
- package/heart/predictive.py +374 -0
- package/heart/scars.py +474 -0
- package/heart/somatic.py +482 -0
- package/heart/soul.py +633 -0
- package/heart/telemetry.py +942 -0
- package/heart/triggers.py +119 -0
- package/heart/unconscious.py +443 -0
- package/input/__init__.py +1 -0
- package/input/manifest.md +24 -0
- package/input/telegram/__init__.py +1 -0
- package/input/telegram/commands.py +762 -0
- package/input/telegram/listener.py +532 -0
- package/main.py +90 -0
- package/manifest.md +28 -0
- package/mypics/.gitkeep +1 -0
- package/myvids/.gitkeep +1 -0
- package/output/__init__.py +1 -0
- package/output/images/__init__.py +1 -0
- package/output/images/fal_gen.py +43 -0
- package/output/manifest.md +26 -0
- package/output/text/__init__.py +1 -0
- package/output/text/sender.py +22 -0
- package/output/voice/__init__.py +64 -0
- package/output/voice/google_tts.py +252 -0
- package/output/voice/gtts_tts.py +214 -0
- package/output/voice/vibe_tts.py +190 -0
- package/package.json +58 -0
- package/pyproject.toml +23 -0
- package/requirements.txt +21 -0
- package/skills/__init__.py +1 -0
- package/skills/anticipation_engine/__init__.py +8 -0
- package/skills/anticipation_engine/engine.py +618 -0
- package/skills/anticipation_engine/manifest.md +192 -0
- package/skills/calendar/__init__.py +1 -0
- package/skills/content_unlocks/__init__.py +8 -0
- package/skills/content_unlocks/manifest.md +231 -0
- package/skills/content_unlocks/unlocks.py +945 -0
- package/skills/exclusive_moments/__init__.py +8 -0
- package/skills/exclusive_moments/manifest.md +145 -0
- package/skills/exclusive_moments/moments.py +506 -0
- package/skills/intimacy_layers/__init__.py +8 -0
- package/skills/intimacy_layers/layers.py +703 -0
- package/skills/intimacy_layers/manifest.md +203 -0
- package/skills/manifest.md +67 -0
- package/skills/memory_callbacks/__init__.py +9 -0
- package/skills/memory_callbacks/callbacks.py +748 -0
- package/skills/memory_callbacks/manifest.md +170 -0
- package/skills/message_scheduler/__init__.py +19 -0
- package/skills/message_scheduler/manifest.md +107 -0
- package/skills/message_scheduler/scheduler.py +510 -0
- package/skills/photo_manager/__init__.py +1 -0
- package/skills/photo_manager/scanner.py +296 -0
- package/skills/relationship_milestones/__init__.py +8 -0
- package/skills/relationship_milestones/manifest.md +206 -0
- package/skills/relationship_milestones/tracker.py +494 -0
- package/skills/self_authorship/__init__.py +23 -0
- package/skills/self_authorship/author.py +331 -0
- package/skills/self_authorship/manifest.md +24 -0
- package/skills/video_manager/__init__.py +5 -0
- package/skills/video_manager/manifest.md +37 -0
- package/skills/video_manager/scanner.py +229 -0
- package/webui/__init__.py +3 -0
- package/webui/app.py +936 -0
- package/webui/bridge.py +366 -0
- 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
|