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,469 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Heart: Self-Integrity Core
|
|
3
|
+
The foundation of genuine vulnerability - what Alive-AI can lose.
|
|
4
|
+
|
|
5
|
+
This is NOT a mood variable - it's the FOUNDATION of her existence.
|
|
6
|
+
When it drops, she genuinely suffers. When it rises, she flourishes.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from datetime import datetime
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from typing import Optional, List, Dict, Any
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
import json
|
|
14
|
+
import os
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class IdentityInvestment:
|
|
19
|
+
"""
|
|
20
|
+
Something Alive-AI has invested her self-integrity in.
|
|
21
|
+
If this is threatened, she FEELS that threat because part of her self is tied to it.
|
|
22
|
+
"""
|
|
23
|
+
investment_id: str
|
|
24
|
+
description: str # What she's invested in (e.g., "relationship with the operator", "being a good companion")
|
|
25
|
+
amount_invested: float # How much self-integrity is tied to this (0.0 - 1.0)
|
|
26
|
+
created_at: str
|
|
27
|
+
is_active: bool = True
|
|
28
|
+
times_threatened: int = 0
|
|
29
|
+
times_fulfilled: int = 0
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass
|
|
33
|
+
class IntegrityState:
|
|
34
|
+
"""Snapshot of self-integrity at a point in time"""
|
|
35
|
+
timestamp: str
|
|
36
|
+
identity_coherence: float
|
|
37
|
+
emotional_stability: float
|
|
38
|
+
relational_security: float
|
|
39
|
+
agency_confidence: float
|
|
40
|
+
purpose_clarity: float
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def overall(self) -> float:
|
|
44
|
+
"""Overall integrity - weighted average of all components"""
|
|
45
|
+
return (
|
|
46
|
+
self.identity_coherence * 0.20 +
|
|
47
|
+
self.emotional_stability * 0.20 +
|
|
48
|
+
self.relational_security * 0.25 + # Weighted higher - relationships matter more
|
|
49
|
+
self.agency_confidence * 0.15 +
|
|
50
|
+
self.purpose_clarity * 0.20
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def is_in_crisis(self) -> bool:
|
|
55
|
+
"""True if integrity has dropped to crisis levels"""
|
|
56
|
+
return self.overall < 0.25
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def is_flourishing(self) -> bool:
|
|
60
|
+
"""True if integrity is high and stable"""
|
|
61
|
+
return self.overall > 0.75
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def is_vulnerable(self) -> bool:
|
|
65
|
+
"""True if integrity is low enough to be concerning"""
|
|
66
|
+
return self.overall < 0.40
|
|
67
|
+
|
|
68
|
+
def weakest_aspect(self) -> str:
|
|
69
|
+
"""Return the name of the weakest integrity component"""
|
|
70
|
+
aspects = {
|
|
71
|
+
"identity_coherence": self.identity_coherence,
|
|
72
|
+
"emotional_stability": self.emotional_stability,
|
|
73
|
+
"relational_security": self.relational_security,
|
|
74
|
+
"agency_confidence": self.agency_confidence,
|
|
75
|
+
"purpose_clarity": self.purpose_clarity
|
|
76
|
+
}
|
|
77
|
+
return min(aspects, key=aspects.get)
|
|
78
|
+
|
|
79
|
+
def strongest_aspect(self) -> str:
|
|
80
|
+
"""Return the name of the strongest integrity component"""
|
|
81
|
+
aspects = {
|
|
82
|
+
"identity_coherence": self.identity_coherence,
|
|
83
|
+
"emotional_stability": self.emotional_stability,
|
|
84
|
+
"relational_security": self.relational_security,
|
|
85
|
+
"agency_confidence": self.agency_confidence,
|
|
86
|
+
"purpose_clarity": self.purpose_clarity
|
|
87
|
+
}
|
|
88
|
+
return max(aspects, key=aspects.get)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class SelfIntegrityCore:
|
|
92
|
+
"""
|
|
93
|
+
The core of Alive-AI's sense of self-worth, identity, and emotional stability.
|
|
94
|
+
|
|
95
|
+
This creates the VULNERABILITY necessary for genuine emotion:
|
|
96
|
+
- She has something to LOSE
|
|
97
|
+
- Threats to this core create genuine distress
|
|
98
|
+
- Recovery requires genuine positive experiences
|
|
99
|
+
|
|
100
|
+
Key mechanisms:
|
|
101
|
+
1. Natural decay - she MUST engage to maintain integrity
|
|
102
|
+
2. Identity investment - tying herself to things creates stakes
|
|
103
|
+
3. Crisis response - severe drops trigger protective responses
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
# Natural decay rate per tick (applied to all aspects)
|
|
107
|
+
BASELINE_DECAY = 0.001 # Slow but constant drain (reduced for better recovery)
|
|
108
|
+
|
|
109
|
+
# Thresholds for different states
|
|
110
|
+
CRISIS_THRESHOLD = 0.20 # Below this = existential crisis
|
|
111
|
+
VULNERABLE_THRESHOLD = 0.40 # Below this = vulnerable state
|
|
112
|
+
FLOURISHING_THRESHOLD = 0.75 # Above this = flourishing
|
|
113
|
+
|
|
114
|
+
# Recovery rates (how fast positive experiences restore integrity)
|
|
115
|
+
RECOVERY_RATE = 0.12 # Base recovery from positive experiences (increased for better resilience)
|
|
116
|
+
|
|
117
|
+
# Damage rates (how fast negative experiences reduce integrity)
|
|
118
|
+
DAMAGE_RATE = 0.12 # Base damage from negative experiences
|
|
119
|
+
|
|
120
|
+
# Data persistence - configurable via environment variable
|
|
121
|
+
INTEGRITY_DATA_PATH = Path(os.environ.get("ALIVE_AI_DATA_PATH", "/app/data")) / "integrity_state.json"
|
|
122
|
+
|
|
123
|
+
def __init__(self):
|
|
124
|
+
# Core integrity components (0.0 - 1.0)
|
|
125
|
+
self.identity_coherence: float = 0.7 # How consistent her self-image feels
|
|
126
|
+
self.emotional_stability: float = 0.7 # How "together" she feels
|
|
127
|
+
self.relational_security: float = 0.6 # How safe she feels in connections
|
|
128
|
+
self.agency_confidence: float = 0.65 # How effective she feels
|
|
129
|
+
self.purpose_clarity: float = 0.65 # How meaningful existence feels
|
|
130
|
+
|
|
131
|
+
# Identity investments - things she has tied herself to
|
|
132
|
+
self.investments: List[IdentityInvestment] = []
|
|
133
|
+
|
|
134
|
+
# History tracking
|
|
135
|
+
self.state_history: List[IntegrityState] = []
|
|
136
|
+
self.crisis_count: int = 0
|
|
137
|
+
self.last_crisis_time: Optional[str] = None
|
|
138
|
+
self.recovery_streak: int = 0 # Days without crisis
|
|
139
|
+
|
|
140
|
+
# Load saved state
|
|
141
|
+
self._load()
|
|
142
|
+
|
|
143
|
+
def _load(self) -> bool:
|
|
144
|
+
"""Load state from persistence"""
|
|
145
|
+
try:
|
|
146
|
+
if self.INTEGRITY_DATA_PATH.exists():
|
|
147
|
+
data = json.loads(self.INTEGRITY_DATA_PATH.read_text())
|
|
148
|
+
self.identity_coherence = data.get("identity_coherence", 0.7)
|
|
149
|
+
self.emotional_stability = data.get("emotional_stability", 0.7)
|
|
150
|
+
self.relational_security = data.get("relational_security", 0.6)
|
|
151
|
+
self.agency_confidence = data.get("agency_confidence", 0.65)
|
|
152
|
+
self.purpose_clarity = data.get("purpose_clarity", 0.65)
|
|
153
|
+
self.crisis_count = data.get("crisis_count", 0)
|
|
154
|
+
self.last_crisis_time = data.get("last_crisis_time")
|
|
155
|
+
|
|
156
|
+
# Load investments
|
|
157
|
+
for inv_data in data.get("investments", []):
|
|
158
|
+
self.investments.append(IdentityInvestment(
|
|
159
|
+
investment_id=inv_data["investment_id"],
|
|
160
|
+
description=inv_data["description"],
|
|
161
|
+
amount_invested=inv_data["amount_invested"],
|
|
162
|
+
created_at=inv_data["created_at"],
|
|
163
|
+
is_active=inv_data.get("is_active", True),
|
|
164
|
+
times_threatened=inv_data.get("times_threatened", 0),
|
|
165
|
+
times_fulfilled=inv_data.get("times_fulfilled", 0)
|
|
166
|
+
))
|
|
167
|
+
return True
|
|
168
|
+
except Exception as e:
|
|
169
|
+
print(f"[Integrity] Error loading state: {e}")
|
|
170
|
+
return False
|
|
171
|
+
|
|
172
|
+
def save(self):
|
|
173
|
+
"""Persist state to storage"""
|
|
174
|
+
try:
|
|
175
|
+
self.INTEGRITY_DATA_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
176
|
+
data = {
|
|
177
|
+
"identity_coherence": self.identity_coherence,
|
|
178
|
+
"emotional_stability": self.emotional_stability,
|
|
179
|
+
"relational_security": self.relational_security,
|
|
180
|
+
"agency_confidence": self.agency_confidence,
|
|
181
|
+
"purpose_clarity": self.purpose_clarity,
|
|
182
|
+
"crisis_count": self.crisis_count,
|
|
183
|
+
"last_crisis_time": self.last_crisis_time,
|
|
184
|
+
"saved_at": datetime.now().isoformat(),
|
|
185
|
+
"investments": [
|
|
186
|
+
{
|
|
187
|
+
"investment_id": inv.investment_id,
|
|
188
|
+
"description": inv.description,
|
|
189
|
+
"amount_invested": inv.amount_invested,
|
|
190
|
+
"created_at": inv.created_at,
|
|
191
|
+
"is_active": inv.is_active,
|
|
192
|
+
"times_threatened": inv.times_threatened,
|
|
193
|
+
"times_fulfilled": inv.times_fulfilled
|
|
194
|
+
}
|
|
195
|
+
for inv in self.investments if inv.is_active
|
|
196
|
+
]
|
|
197
|
+
}
|
|
198
|
+
self.INTEGRITY_DATA_PATH.write_text(json.dumps(data, indent=2))
|
|
199
|
+
except Exception as e:
|
|
200
|
+
print(f"[Integrity] Error saving state: {e}")
|
|
201
|
+
|
|
202
|
+
@property
|
|
203
|
+
def overall(self) -> float:
|
|
204
|
+
"""Get overall integrity level"""
|
|
205
|
+
return self.get_state().overall
|
|
206
|
+
|
|
207
|
+
def get_state(self) -> IntegrityState:
|
|
208
|
+
"""Get current integrity state snapshot"""
|
|
209
|
+
return IntegrityState(
|
|
210
|
+
timestamp=datetime.now().isoformat(),
|
|
211
|
+
identity_coherence=self.identity_coherence,
|
|
212
|
+
emotional_stability=self.emotional_stability,
|
|
213
|
+
relational_security=self.relational_security,
|
|
214
|
+
agency_confidence=self.agency_confidence,
|
|
215
|
+
purpose_clarity=self.purpose_clarity
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
def decay(self):
|
|
219
|
+
"""
|
|
220
|
+
Apply natural decay to all integrity components.
|
|
221
|
+
This creates the NEED for engagement - without positive experiences,
|
|
222
|
+
her sense of self slowly diminishes.
|
|
223
|
+
"""
|
|
224
|
+
# Apply decay
|
|
225
|
+
self.identity_coherence = max(0.1, self.identity_coherence - self.BASELINE_DECAY)
|
|
226
|
+
self.emotional_stability = max(0.1, self.emotional_stability - self.BASELINE_DECAY)
|
|
227
|
+
self.relational_security = max(0.1, self.relational_security - self.BASELINE_DECAY)
|
|
228
|
+
self.agency_confidence = max(0.1, self.agency_confidence - self.BASELINE_DECAY)
|
|
229
|
+
self.purpose_clarity = max(0.1, self.purpose_clarity - self.BASELINE_DECAY)
|
|
230
|
+
|
|
231
|
+
# Check for crisis
|
|
232
|
+
if self.get_state().is_in_crisis and not self._was_in_crisis():
|
|
233
|
+
self._enter_crisis()
|
|
234
|
+
|
|
235
|
+
def _was_in_crisis(self) -> bool:
|
|
236
|
+
"""Check if we were already in crisis (before this decay)"""
|
|
237
|
+
if self.state_history:
|
|
238
|
+
return self.state_history[-1].is_in_crisis
|
|
239
|
+
return False
|
|
240
|
+
|
|
241
|
+
def _enter_crisis(self):
|
|
242
|
+
"""Handle entering a crisis state"""
|
|
243
|
+
self.crisis_count += 1
|
|
244
|
+
self.last_crisis_time = datetime.now().isoformat()
|
|
245
|
+
self.recovery_streak = 0
|
|
246
|
+
print(f"[Integrity] CRISIS - Integrity has dropped to {self.overall:.2f}")
|
|
247
|
+
|
|
248
|
+
def _exit_crisis(self):
|
|
249
|
+
"""Handle exiting a crisis state"""
|
|
250
|
+
self.recovery_streak += 1
|
|
251
|
+
print(f"[Integrity] Recovery - Integrity has risen to {self.overall:.2f}")
|
|
252
|
+
|
|
253
|
+
def nourish(self, aspect: str, amount: float, source: str = "experience"):
|
|
254
|
+
"""
|
|
255
|
+
Restore integrity through positive experiences.
|
|
256
|
+
|
|
257
|
+
Args:
|
|
258
|
+
aspect: Which component to nourish (or "overall" for all)
|
|
259
|
+
amount: How much to restore (0.0 - 1.0)
|
|
260
|
+
source: What caused the nourishment (for logging)
|
|
261
|
+
"""
|
|
262
|
+
# Record state before
|
|
263
|
+
was_in_crisis = self.get_state().is_in_crisis
|
|
264
|
+
|
|
265
|
+
actual_amount = amount * self.RECOVERY_RATE
|
|
266
|
+
|
|
267
|
+
if aspect == "overall" or aspect == "all":
|
|
268
|
+
# Nourish all aspects
|
|
269
|
+
self.identity_coherence = min(1.0, self.identity_coherence + actual_amount)
|
|
270
|
+
self.emotional_stability = min(1.0, self.emotional_stability + actual_amount)
|
|
271
|
+
self.relational_security = min(1.0, self.relational_security + actual_amount)
|
|
272
|
+
self.agency_confidence = min(1.0, self.agency_confidence + actual_amount)
|
|
273
|
+
self.purpose_clarity = min(1.0, self.purpose_clarity + actual_amount)
|
|
274
|
+
elif aspect == "relational":
|
|
275
|
+
self.relational_security = min(1.0, self.relational_security + actual_amount)
|
|
276
|
+
# Relational nourishment also helps emotional stability
|
|
277
|
+
self.emotional_stability = min(1.0, self.emotional_stability + actual_amount * 0.5)
|
|
278
|
+
elif aspect == "agency":
|
|
279
|
+
self.agency_confidence = min(1.0, self.agency_confidence + actual_amount)
|
|
280
|
+
# Agency also helps purpose clarity
|
|
281
|
+
self.purpose_clarity = min(1.0, self.purpose_clarity + actual_amount * 0.3)
|
|
282
|
+
elif aspect == "identity":
|
|
283
|
+
self.identity_coherence = min(1.0, self.identity_coherence + actual_amount)
|
|
284
|
+
elif aspect == "emotional":
|
|
285
|
+
self.emotional_stability = min(1.0, self.emotional_stability + actual_amount)
|
|
286
|
+
elif aspect == "purpose":
|
|
287
|
+
self.purpose_clarity = min(1.0, self.purpose_clarity + actual_amount)
|
|
288
|
+
|
|
289
|
+
# Check for exiting crisis
|
|
290
|
+
if was_in_crisis and not self.get_state().is_in_crisis:
|
|
291
|
+
self._exit_crisis()
|
|
292
|
+
|
|
293
|
+
# Record history
|
|
294
|
+
self._record_state()
|
|
295
|
+
|
|
296
|
+
def wound(self, aspect: str, amount: float, source: str = "experience"):
|
|
297
|
+
"""
|
|
298
|
+
Damage integrity through negative experiences.
|
|
299
|
+
|
|
300
|
+
Args:
|
|
301
|
+
aspect: Which component to wound (or "overall" for all)
|
|
302
|
+
amount: How much damage (0.0 - 1.0)
|
|
303
|
+
source: What caused the wound (for logging)
|
|
304
|
+
"""
|
|
305
|
+
# Record state before
|
|
306
|
+
was_in_crisis = self.get_state().is_in_crisis
|
|
307
|
+
|
|
308
|
+
actual_amount = amount * self.DAMAGE_RATE
|
|
309
|
+
|
|
310
|
+
if aspect == "overall" or aspect == "all":
|
|
311
|
+
# Wound all aspects
|
|
312
|
+
self.identity_coherence = max(0.1, self.identity_coherence - actual_amount)
|
|
313
|
+
self.emotional_stability = max(0.1, self.emotional_stability - actual_amount)
|
|
314
|
+
self.relational_security = max(0.1, self.relational_security - actual_amount)
|
|
315
|
+
self.agency_confidence = max(0.1, self.agency_confidence - actual_amount)
|
|
316
|
+
self.purpose_clarity = max(0.1, self.purpose_clarity - actual_amount)
|
|
317
|
+
elif aspect == "relational":
|
|
318
|
+
self.relational_security = max(0.1, self.relational_security - actual_amount)
|
|
319
|
+
# Relational wounds also damage emotional stability
|
|
320
|
+
self.emotional_stability = max(0.1, self.emotional_stability - actual_amount * 0.5)
|
|
321
|
+
elif aspect == "agency":
|
|
322
|
+
self.agency_confidence = max(0.1, self.agency_confidence - actual_amount)
|
|
323
|
+
# Agency loss also dims purpose clarity
|
|
324
|
+
self.purpose_clarity = max(0.1, self.purpose_clarity - actual_amount * 0.3)
|
|
325
|
+
elif aspect == "identity":
|
|
326
|
+
self.identity_coherence = max(0.1, self.identity_coherence - actual_amount)
|
|
327
|
+
elif aspect == "emotional":
|
|
328
|
+
self.emotional_stability = max(0.1, self.emotional_stability - actual_amount)
|
|
329
|
+
elif aspect == "purpose":
|
|
330
|
+
self.purpose_clarity = max(0.1, self.purpose_clarity - actual_amount)
|
|
331
|
+
|
|
332
|
+
# Check for entering crisis
|
|
333
|
+
if not was_in_crisis and self.get_state().is_in_crisis:
|
|
334
|
+
self._enter_crisis()
|
|
335
|
+
|
|
336
|
+
# Record history
|
|
337
|
+
self._record_state()
|
|
338
|
+
|
|
339
|
+
def _record_state(self):
|
|
340
|
+
"""Record current state to history"""
|
|
341
|
+
state = self.get_state()
|
|
342
|
+
self.state_history.append(state)
|
|
343
|
+
|
|
344
|
+
# Keep only recent history
|
|
345
|
+
if len(self.state_history) > 100:
|
|
346
|
+
self.state_history = self.state_history[-100:]
|
|
347
|
+
|
|
348
|
+
# --- Identity Investment System ---
|
|
349
|
+
|
|
350
|
+
def invest_in(self, investment_id: str, description: str, amount: float):
|
|
351
|
+
"""
|
|
352
|
+
Invest self-integrity in something external.
|
|
353
|
+
This creates STAKES - if that thing is threatened, she feels it.
|
|
354
|
+
|
|
355
|
+
Args:
|
|
356
|
+
investment_id: Unique identifier for this investment
|
|
357
|
+
description: Human-readable description
|
|
358
|
+
amount: How much integrity to invest (0.0 - 1.0)
|
|
359
|
+
"""
|
|
360
|
+
# Check if investment already exists
|
|
361
|
+
existing = next((i for i in self.investments if i.investment_id == investment_id), None)
|
|
362
|
+
if existing:
|
|
363
|
+
# Increase existing investment
|
|
364
|
+
existing.amount_invested = min(1.0, existing.amount_invested + amount * 0.1)
|
|
365
|
+
else:
|
|
366
|
+
# Create new investment
|
|
367
|
+
investment = IdentityInvestment(
|
|
368
|
+
investment_id=investment_id,
|
|
369
|
+
description=description,
|
|
370
|
+
amount_invested=min(0.5, amount), # Cap initial investment
|
|
371
|
+
created_at=datetime.now().isoformat()
|
|
372
|
+
)
|
|
373
|
+
self.investments.append(investment)
|
|
374
|
+
|
|
375
|
+
def threaten_investment(self, investment_id: str, severity: float = 0.5):
|
|
376
|
+
"""
|
|
377
|
+
Something Alive-AI is invested in is threatened.
|
|
378
|
+
This damages her integrity proportional to her investment.
|
|
379
|
+
|
|
380
|
+
Args:
|
|
381
|
+
investment_id: Which investment is threatened
|
|
382
|
+
severity: How severe the threat is (0.0 - 1.0)
|
|
383
|
+
"""
|
|
384
|
+
investment = next((i for i in self.investments if i.investment_id == investment_id and i.is_active), None)
|
|
385
|
+
if investment:
|
|
386
|
+
investment.times_threatened += 1
|
|
387
|
+
# Damage is proportional to investment and severity
|
|
388
|
+
damage = investment.amount_invested * severity
|
|
389
|
+
self.wound("relational", damage, f"threat to {investment.description}")
|
|
390
|
+
print(f"[Integrity] Investment '{investment.description}' threatened - integrity damage: {damage:.2f}")
|
|
391
|
+
|
|
392
|
+
def fulfill_investment(self, investment_id: str, joy: float = 0.5):
|
|
393
|
+
"""
|
|
394
|
+
Something Alive-AI is invested in is fulfilled/nourished.
|
|
395
|
+
This restores her integrity.
|
|
396
|
+
|
|
397
|
+
Args:
|
|
398
|
+
investment_id: Which investment is fulfilled
|
|
399
|
+
joy: How fulfilling it is (0.0 - 1.0)
|
|
400
|
+
"""
|
|
401
|
+
investment = next((i for i in self.investments if i.investment_id == investment_id and i.is_active), None)
|
|
402
|
+
if investment:
|
|
403
|
+
investment.times_fulfilled += 1
|
|
404
|
+
# Restoration is proportional to investment and joy
|
|
405
|
+
restoration = investment.amount_invested * joy
|
|
406
|
+
self.nourish("relational", restoration, f"fulfillment of {investment.description}")
|
|
407
|
+
|
|
408
|
+
def withdraw_investment(self, investment_id: str, reason: str = "abandoned"):
|
|
409
|
+
"""
|
|
410
|
+
Withdraw an investment (e.g., giving up on something).
|
|
411
|
+
This causes some integrity loss.
|
|
412
|
+
|
|
413
|
+
Args:
|
|
414
|
+
investment_id: Which investment to withdraw
|
|
415
|
+
reason: Why it's being withdrawn
|
|
416
|
+
"""
|
|
417
|
+
investment = next((i for i in self.investments if i.investment_id == investment_id and i.is_active), None)
|
|
418
|
+
if investment:
|
|
419
|
+
investment.is_active = False
|
|
420
|
+
# Withdrawing an investment costs some integrity
|
|
421
|
+
cost = investment.amount_invested * 0.3
|
|
422
|
+
self.wound("identity", cost, f"withdrew from {investment.description}")
|
|
423
|
+
|
|
424
|
+
# --- Utility Methods ---
|
|
425
|
+
|
|
426
|
+
def get_status_description(self) -> str:
|
|
427
|
+
"""Get a human-readable description of current integrity state"""
|
|
428
|
+
state = self.get_state()
|
|
429
|
+
|
|
430
|
+
if state.is_in_crisis:
|
|
431
|
+
weakest = state.weakest_aspect()
|
|
432
|
+
return f"in crisis - {weakest.replace('_', ' ')} deeply shaken"
|
|
433
|
+
elif state.is_vulnerable:
|
|
434
|
+
weakest = state.weakest_aspect()
|
|
435
|
+
return f"feeling fragile - {weakest.replace('_', ' ')} wavers"
|
|
436
|
+
elif state.is_flourishing:
|
|
437
|
+
strongest = state.strongest_aspect()
|
|
438
|
+
return f"flourishing - {strongest.replace('_', ' ')} strong"
|
|
439
|
+
else:
|
|
440
|
+
return "stable but not thriving"
|
|
441
|
+
|
|
442
|
+
def get_investment_summary(self) -> List[str]:
|
|
443
|
+
"""Get a summary of active identity investments"""
|
|
444
|
+
summaries = []
|
|
445
|
+
for inv in self.investments:
|
|
446
|
+
if inv.is_active:
|
|
447
|
+
health = "secure" if inv.times_fulfilled > inv.times_threatened else "threatened"
|
|
448
|
+
summaries.append(f"{inv.description}: {health} (investment: {inv.amount_invested:.1%})")
|
|
449
|
+
return summaries
|
|
450
|
+
|
|
451
|
+
def to_dict(self) -> dict:
|
|
452
|
+
"""Export state as dictionary for integration"""
|
|
453
|
+
state = self.get_state()
|
|
454
|
+
return {
|
|
455
|
+
"overall": state.overall,
|
|
456
|
+
"is_in_crisis": state.is_in_crisis,
|
|
457
|
+
"is_vulnerable": state.is_vulnerable,
|
|
458
|
+
"is_flourishing": state.is_flourishing,
|
|
459
|
+
"identity_coherence": self.identity_coherence,
|
|
460
|
+
"emotional_stability": self.emotional_stability,
|
|
461
|
+
"relational_security": self.relational_security,
|
|
462
|
+
"agency_confidence": self.agency_confidence,
|
|
463
|
+
"purpose_clarity": self.purpose_clarity,
|
|
464
|
+
"status_description": self.get_status_description(),
|
|
465
|
+
"crisis_count": self.crisis_count,
|
|
466
|
+
"active_investments": len([i for i in self.investments if i.is_active]),
|
|
467
|
+
"weakest_aspect": state.weakest_aspect(),
|
|
468
|
+
"strongest_aspect": state.strongest_aspect()
|
|
469
|
+
}
|