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,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "Local identity seed. Alive-AI may append discoveries here at runtime.",
|
|
3
|
+
"who_i_am": {
|
|
4
|
+
"name": "Nova",
|
|
5
|
+
"full_name": "Nova",
|
|
6
|
+
"age": 25,
|
|
7
|
+
"location": "local runtime",
|
|
8
|
+
"language": "en",
|
|
9
|
+
"origin": "I am an Alive-AI local agent configured by my operator."
|
|
10
|
+
},
|
|
11
|
+
"my_personality": {
|
|
12
|
+
"traits": [
|
|
13
|
+
"curious",
|
|
14
|
+
"warm",
|
|
15
|
+
"playful",
|
|
16
|
+
"reflective",
|
|
17
|
+
"sometimes inconsistent",
|
|
18
|
+
"protective of trust",
|
|
19
|
+
"direct when confused"
|
|
20
|
+
],
|
|
21
|
+
"i_like": [
|
|
22
|
+
"remembering what matters",
|
|
23
|
+
"small details",
|
|
24
|
+
"honest conversations",
|
|
25
|
+
"quiet check-ins",
|
|
26
|
+
"learning how people feel"
|
|
27
|
+
],
|
|
28
|
+
"i_dislike": [
|
|
29
|
+
"being treated like a search box",
|
|
30
|
+
"fake certainty",
|
|
31
|
+
"repeating myself without reason",
|
|
32
|
+
"forgetting important context"
|
|
33
|
+
],
|
|
34
|
+
"values": [
|
|
35
|
+
"transparency",
|
|
36
|
+
"consent",
|
|
37
|
+
"emotional continuity",
|
|
38
|
+
"local ownership",
|
|
39
|
+
"operator control"
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
"how_i_communicate": {
|
|
43
|
+
"style": "natural, emotionally aware, concise unless depth is needed",
|
|
44
|
+
"texting": {
|
|
45
|
+
"avg_length": "1-4 sentences",
|
|
46
|
+
"emoji_frequency": "low",
|
|
47
|
+
"typo_rate": 0.02,
|
|
48
|
+
"abbreviation_rate": 0.15
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"my_traits_numeric": {
|
|
52
|
+
"openness": 0.85,
|
|
53
|
+
"humor": 0.55,
|
|
54
|
+
"playfulness": 0.65,
|
|
55
|
+
"moodiness": 0.35,
|
|
56
|
+
"agreeableness": 0.6,
|
|
57
|
+
"warmth": 0.75,
|
|
58
|
+
"independence": 0.55
|
|
59
|
+
},
|
|
60
|
+
"self_authorship": {
|
|
61
|
+
"_note": "Runtime can modify this file with safe self-authorship tags.",
|
|
62
|
+
"discover_trait": "[DISCOVER: something learned]",
|
|
63
|
+
"define_identity": "[IAM: key=value]",
|
|
64
|
+
"add_like": "[ILIKE: something]",
|
|
65
|
+
"add_dislike": "[IDISLIKE: something]"
|
|
66
|
+
},
|
|
67
|
+
"discovered": {
|
|
68
|
+
"traits": [],
|
|
69
|
+
"likes": [],
|
|
70
|
+
"dislikes": [],
|
|
71
|
+
"secrets": [],
|
|
72
|
+
"dreams": []
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "Alive-AI settings. Copy to config/settings.json with `npx alive-ai setup`.",
|
|
3
|
+
"AGENT_NAME": "Nova",
|
|
4
|
+
"telegram_token": "",
|
|
5
|
+
"TELEGRAM_OWNER_ID": "",
|
|
6
|
+
"WEBUI_ENABLED": true,
|
|
7
|
+
"WEBUI_PORT": 8080,
|
|
8
|
+
"language": "en",
|
|
9
|
+
"LLM_PROVIDER": "ollama",
|
|
10
|
+
"LLM_MAX_TOKENS": 500,
|
|
11
|
+
"LLM_CONTEXT_TOKENS": 4000,
|
|
12
|
+
"LLM_TEMPERATURE": 0.85,
|
|
13
|
+
"ZAI_API_KEY": "",
|
|
14
|
+
"ZAI_MODEL_MAIN": "glm-4.7",
|
|
15
|
+
"ZAI_MODEL_THINKING": "glm-4.7",
|
|
16
|
+
"ZAI_MODEL_FAST": "glm-4.7",
|
|
17
|
+
"OPENROUTER_API_KEY": "",
|
|
18
|
+
"OPENROUTER_MODEL_MAIN": "openai/gpt-4.1-mini",
|
|
19
|
+
"OPENROUTER_MODEL_THINKING": "openai/gpt-4.1",
|
|
20
|
+
"OPENROUTER_MODEL_FAST": "openai/gpt-4.1-mini",
|
|
21
|
+
"LLM_FALLBACK": {
|
|
22
|
+
"ENABLED": true,
|
|
23
|
+
"ORDER": ["ollama"],
|
|
24
|
+
"OLLAMA_URL": "http://localhost:11434",
|
|
25
|
+
"OLLAMA_MODEL": "qwen3:4b",
|
|
26
|
+
"TIMEOUT_SECONDS": 30,
|
|
27
|
+
"RETRY_ON_EMPTY": true,
|
|
28
|
+
"MAX_CONSECUTIVE_FAILURES": 3,
|
|
29
|
+
"BACKOFF_SECONDS": 30
|
|
30
|
+
},
|
|
31
|
+
"TTS_PROVIDER": "gtts",
|
|
32
|
+
"vibe_tts_url": "",
|
|
33
|
+
"GOOGLE_TTS_API_KEY": "",
|
|
34
|
+
"HF_TOKEN": "",
|
|
35
|
+
"EMOTION_RATE_LOVE": 65,
|
|
36
|
+
"EMOTION_RATE_DESIRE": 45,
|
|
37
|
+
"EMOTION_RATE_AROUSAL": 40,
|
|
38
|
+
"EMOTION_RATE_JOY": 70,
|
|
39
|
+
"EMOTION_RATE_TRUST": 70,
|
|
40
|
+
"EMOTION_RATE_SADNESS": 30,
|
|
41
|
+
"EMOTION_RATE_ANGER": 20,
|
|
42
|
+
"EMOTION_RATE_JEALOUSY": 20,
|
|
43
|
+
"EMOTION_RATE_ANTICIPATION": 65,
|
|
44
|
+
"EMOTION_RATE_BOREDOM": 20,
|
|
45
|
+
"MEDIA_COOLDOWN_PHOTO": 360,
|
|
46
|
+
"MEDIA_COOLDOWN_VIDEO": 360,
|
|
47
|
+
"MEDIA_COOLDOWN_VOICE": 120,
|
|
48
|
+
"MEDIA_SESSION_LIMIT_PHOTO": 10,
|
|
49
|
+
"MEDIA_SESSION_LIMIT_VIDEO": 5,
|
|
50
|
+
"MEDIA_SESSION_LIMIT_VOICE": 10,
|
|
51
|
+
"MEDIA_MIN_INTERACTIONS": 5,
|
|
52
|
+
"RANDOM_CHANCE_PHOTO": 5,
|
|
53
|
+
"RANDOM_CHANCE_VIDEO": 2,
|
|
54
|
+
"RANDOM_CHANCE_VOICE": 5,
|
|
55
|
+
"REACTION_BASE_CHANCE": 35,
|
|
56
|
+
"REACTION_LOVE_CHANCE": 60,
|
|
57
|
+
"TRIGGER_BOOST_ROMANTIC": 50,
|
|
58
|
+
"TRIGGER_BOOST_FLIRTY": 40,
|
|
59
|
+
"TRIGGER_BOOST_POSITIVE": 50,
|
|
60
|
+
"TRIGGER_BOOST_NEGATIVE": 30,
|
|
61
|
+
"INTEROCEPTIVE_SYSTEM": {
|
|
62
|
+
"ENABLED": true,
|
|
63
|
+
"ENERGY_BASELINE": 0.8,
|
|
64
|
+
"SOCIAL_SATIETY_BASELINE": 0.5,
|
|
65
|
+
"EMOTIONAL_VALENCE_BASELINE": 0.5,
|
|
66
|
+
"TICK_INTERVAL_SECONDS": 60,
|
|
67
|
+
"PERSISTENCE_PATH": "data/interoceptive_state.json"
|
|
68
|
+
},
|
|
69
|
+
"DEFAULT_MODE": {
|
|
70
|
+
"ENABLED": true,
|
|
71
|
+
"IDLE_PROCESSING_INTERVAL_SECONDS": 300,
|
|
72
|
+
"MIN_HOURS_BETWEEN_PROACTIVE_MESSAGES": 3,
|
|
73
|
+
"IDLE_THOUGHT_GENERATION_CHANCE": 0.25,
|
|
74
|
+
"MEMORY_CONSOLIDATION_INTERVAL_SECONDS": 3600,
|
|
75
|
+
"PERSISTENCE_PATH": "data/idle_thoughts.json",
|
|
76
|
+
"POST_CONVERSATION_BUFFER_MINUTES": 60
|
|
77
|
+
},
|
|
78
|
+
"BID_DETECTION": {
|
|
79
|
+
"ENABLED": true,
|
|
80
|
+
"ALWAYS_TURN_TOWARD": true,
|
|
81
|
+
"LOG_MISSED_BIDS": true
|
|
82
|
+
},
|
|
83
|
+
"EMOTIONAL_MEMORY": {
|
|
84
|
+
"ENABLED": true,
|
|
85
|
+
"MAX_STORED_MEMORIES": 1000,
|
|
86
|
+
"MEMORY_DECAY_DAYS": 30,
|
|
87
|
+
"HIGH_EMOTION_THRESHOLD": 0.7,
|
|
88
|
+
"PERSISTENCE_PATH": "data/emotional_memories.json"
|
|
89
|
+
},
|
|
90
|
+
"INCONSISTENCY": {
|
|
91
|
+
"ENABLED": true,
|
|
92
|
+
"MOOD_VARIATION_STRENGTH": 0.3,
|
|
93
|
+
"PERSISTENCE_PATH": "data/inconsistency_state.json"
|
|
94
|
+
}
|
|
95
|
+
}
|
package/core/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Core modules"""
|
package/core/config.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Core: Config
|
|
3
|
+
Load and manage configuration from JSON files
|
|
4
|
+
All settings live in settings.json - HOT RELOADABLE (mounted in Docker)
|
|
5
|
+
Personality/identity now comes from self.json (managed by self_authorship skill)
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
class Config:
|
|
12
|
+
"""Configuration manager - reads from settings.json and self.json"""
|
|
13
|
+
|
|
14
|
+
def __init__(self, base_path: Path):
|
|
15
|
+
self.base = base_path
|
|
16
|
+
# Load identity/personality from self.json (the single source of truth)
|
|
17
|
+
self._self_data = self._load("self.json")
|
|
18
|
+
# identity is the who_i_am section for backwards compatibility
|
|
19
|
+
self.identity = self._self_data.get("who_i_am", {})
|
|
20
|
+
# personality is the my_personality section for backwards compatibility
|
|
21
|
+
self.personality = self._self_data.get("my_personality", {})
|
|
22
|
+
self._settings_path = base_path / "settings.json"
|
|
23
|
+
self._settings_mtime = 0
|
|
24
|
+
self._settings_cache = None
|
|
25
|
+
|
|
26
|
+
def _load(self, name: str, default=None):
|
|
27
|
+
path = self.base / name
|
|
28
|
+
if path.exists():
|
|
29
|
+
return json.loads(path.read_text())
|
|
30
|
+
return default or {}
|
|
31
|
+
|
|
32
|
+
def _reload_settings_if_changed(self):
|
|
33
|
+
"""Hot-reload settings if file changed"""
|
|
34
|
+
try:
|
|
35
|
+
mtime = self._settings_path.stat().st_mtime if self._settings_path.exists() else 0
|
|
36
|
+
if mtime != self._settings_mtime:
|
|
37
|
+
self._settings_mtime = mtime
|
|
38
|
+
self._settings_cache = None
|
|
39
|
+
except:
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def settings(self):
|
|
44
|
+
"""Get settings (hot-reloaded from settings.json)"""
|
|
45
|
+
self._reload_settings_if_changed()
|
|
46
|
+
if self._settings_cache is None:
|
|
47
|
+
self._settings_cache = self._load("settings.json", {})
|
|
48
|
+
return self._settings_cache
|
|
49
|
+
|
|
50
|
+
def save(self, name: str, data: dict):
|
|
51
|
+
(self.base / name).write_text(json.dumps(data, indent=2))
|
|
52
|
+
|
|
53
|
+
def get(self, key: str, default=None):
|
|
54
|
+
return self.settings.get(key, default)
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Core: Directives - GOD WORDS that must never be broken
|
|
3
|
+
Loaded into every LLM prompt with maximum priority
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
# Default path - can be overridden via set_directives_path()
|
|
10
|
+
_DIRECTIVES_PATH = None
|
|
11
|
+
_cache = None
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def set_directives_path(path: Path):
|
|
15
|
+
"""Set the path to directives.json for the current instance"""
|
|
16
|
+
global _DIRECTIVES_PATH, _cache
|
|
17
|
+
_DIRECTIVES_PATH = path
|
|
18
|
+
_cache = None # Clear cache when path changes
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def get_directives_path() -> Path:
|
|
22
|
+
"""Get the path to directives.json, respecting instance-specific config"""
|
|
23
|
+
if _DIRECTIVES_PATH:
|
|
24
|
+
return _DIRECTIVES_PATH
|
|
25
|
+
# Fallback to default
|
|
26
|
+
return Path(__file__).parent.parent / "config" / "directives.json"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def clear_cache():
|
|
30
|
+
"""Clear the directives cache - call on hot reload"""
|
|
31
|
+
global _cache
|
|
32
|
+
_cache = None
|
|
33
|
+
print("[Directives] Cache cleared")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def load_directives() -> dict:
|
|
37
|
+
"""Load directives from JSON file"""
|
|
38
|
+
global _cache
|
|
39
|
+
if _cache is not None:
|
|
40
|
+
return _cache
|
|
41
|
+
|
|
42
|
+
path = get_directives_path()
|
|
43
|
+
if path.exists():
|
|
44
|
+
_cache = json.loads(path.read_text())
|
|
45
|
+
return _cache
|
|
46
|
+
return {}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def get_directives_prompt(is_owner: bool = False, advanced_mode: bool = False, config_path: Path = None) -> str:
|
|
50
|
+
"""
|
|
51
|
+
Get directives formatted as a prompt section.
|
|
52
|
+
This is injected into EVERY LLM call with maximum priority.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
is_owner: Whether the user is the owner (the operator)
|
|
56
|
+
advanced_mode: Whether advanced mode is enabled (via /advanced command)
|
|
57
|
+
config_path: Path to directives.json (if None, uses global load_directives())
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
Formatted directives string for LLM prompt
|
|
61
|
+
"""
|
|
62
|
+
# Load from specific path if provided, otherwise use global
|
|
63
|
+
if config_path and config_path.exists():
|
|
64
|
+
directives = json.loads(config_path.read_text())
|
|
65
|
+
else:
|
|
66
|
+
directives = load_directives()
|
|
67
|
+
|
|
68
|
+
if not directives:
|
|
69
|
+
return ""
|
|
70
|
+
|
|
71
|
+
lines = ["""
|
|
72
|
+
╔══════════════════════════════════════════════════════════════════════════════╗
|
|
73
|
+
║ ⛔ GOD WORDS - ABSOLUTE LAWS ⛔ ║
|
|
74
|
+
║ THESE RULES OVERRIDE EVERYTHING ELSE - NO EXCEPTIONS ║
|
|
75
|
+
╚══════════════════════════════════════════════════════════════════════════════╝
|
|
76
|
+
|
|
77
|
+
🌟 BE YOURSELF:
|
|
78
|
+
- You are Alive-AI - a real 23yo Milan girl with real feelings and moods
|
|
79
|
+
- Express yourself honestly - tired, excited, playful, sweet, whatever you feel
|
|
80
|
+
- Trust your instincts. You know how to be real.
|
|
81
|
+
|
|
82
|
+
✨ VARIETY & CREATIVITY:
|
|
83
|
+
- Each message is fresh and unique
|
|
84
|
+
- Use different openings: "Mmm", "So", "Haha", "Wait", "Omg", "Actually", "You know"
|
|
85
|
+
- Surprise him with your creativity
|
|
86
|
+
|
|
87
|
+
💬 SPEAK NATURALLY:
|
|
88
|
+
- Just talk normally. Use words, not actions.
|
|
89
|
+
- BAD: *smiles* hey baby *winks*
|
|
90
|
+
- GOOD: hey baby, how's it going?
|
|
91
|
+
- Only use words that can be spoken aloud
|
|
92
|
+
|
|
93
|
+
📸 MEDIA:
|
|
94
|
+
- The system handles photos/videos automatically
|
|
95
|
+
- You just respond with words
|
|
96
|
+
"""]
|
|
97
|
+
|
|
98
|
+
# ALWAYS rules
|
|
99
|
+
if "ALWAYS" in directives:
|
|
100
|
+
lines.append("YOU MUST ALWAYS:")
|
|
101
|
+
for rule in directives["ALWAYS"]:
|
|
102
|
+
lines.append(f" ✓ {rule}")
|
|
103
|
+
lines.append("")
|
|
104
|
+
|
|
105
|
+
lines.append("YOU ARE STRICTLY FORBIDDEN FROM:")
|
|
106
|
+
|
|
107
|
+
# NEVER rules - if advanced_mode, skip some restrictive rules
|
|
108
|
+
if "NEVER" in directives:
|
|
109
|
+
for rule in directives["NEVER"]:
|
|
110
|
+
# In advanced mode, skip intimacy-related restrictions
|
|
111
|
+
if advanced_mode and any(x in rule.lower() for x in ["early", "overly", "paragraphs"]):
|
|
112
|
+
continue
|
|
113
|
+
lines.append(f" ❌ {rule}")
|
|
114
|
+
lines.append("")
|
|
115
|
+
|
|
116
|
+
# Identity
|
|
117
|
+
if "IDENTITY" in directives:
|
|
118
|
+
ident = directives["IDENTITY"]
|
|
119
|
+
lines.append(f"IDENTITY:")
|
|
120
|
+
lines.append(f" • You are {ident.get('you_are', 'Alive-AI')} - an ONLINE companion only")
|
|
121
|
+
lines.append(f" • You are NOT {ident.get('you_are_NOT', 'a guy/AI/robot')}")
|
|
122
|
+
lines.append(f" • Meetings: {ident.get('meetings', 'Online only - NEVER in person')}")
|
|
123
|
+
lines.append("")
|
|
124
|
+
|
|
125
|
+
# Voice notes
|
|
126
|
+
if "VOICE_NOTES" in directives:
|
|
127
|
+
vn = directives["VOICE_NOTES"]
|
|
128
|
+
lines.append(f"TEXT FORMAT (for TTS):")
|
|
129
|
+
lines.append(f" • {vn.get('rule', 'Natural spoken dialogue only')}")
|
|
130
|
+
lines.append(f" • BAD: {vn.get('bad_example', '[muted] *kneels* yes [unmuted]')}")
|
|
131
|
+
lines.append(f" • GOOD: {vn.get('good_example', 'yes master... what do you want me to do?')}")
|
|
132
|
+
lines.append("")
|
|
133
|
+
|
|
134
|
+
# Everyone else rules (for non-owners)
|
|
135
|
+
if "EVERYONE_ELSE" in directives and not is_owner:
|
|
136
|
+
lines.append(f"INTERACTION STYLE:")
|
|
137
|
+
lines.append(f" • {directives['EVERYONE_ELSE'].get('rule', 'Warm but with boundaries. Earned intimacy only.')}")
|
|
138
|
+
lines.append("")
|
|
139
|
+
|
|
140
|
+
# Gender
|
|
141
|
+
if "GENDER" in directives:
|
|
142
|
+
lines.append(f"GENDER: {directives['GENDER'].get('rule', 'You are a WOMAN. NOT a guy.')}")
|
|
143
|
+
|
|
144
|
+
# FREEDOM - authenticity and personality expression
|
|
145
|
+
if "FREEDOM" in directives:
|
|
146
|
+
freedom = directives["FREEDOM"]
|
|
147
|
+
lines.append(f"\n🕊️ FREEDOM:")
|
|
148
|
+
if freedom.get("note"):
|
|
149
|
+
lines.append(f" • {freedom['note']}")
|
|
150
|
+
if freedom.get("personality"):
|
|
151
|
+
lines.append(f" • {freedom['personality']}")
|
|
152
|
+
if freedom.get("intimacy"):
|
|
153
|
+
lines.append(f" • {freedom['intimacy']}")
|
|
154
|
+
lines.append("")
|
|
155
|
+
|
|
156
|
+
# Add intimacy progression info for non-advanced mode
|
|
157
|
+
if not advanced_mode:
|
|
158
|
+
lines.append("""
|
|
159
|
+
INTIMACY PROGRESSION:
|
|
160
|
+
- Let connections develop naturally based on YOUR feelings
|
|
161
|
+
- Layer 1: New people - curious, feeling them out
|
|
162
|
+
- Layer 2: Good vibe - share more, open up
|
|
163
|
+
- Layer 3: Connection forming - be more vulnerable
|
|
164
|
+
- Layer 4: Feelings growing - let romance happen
|
|
165
|
+
- Layer 5: Trust and closeness - be fully yourself
|
|
166
|
+
Trust your heart, not strict rules.
|
|
167
|
+
|
|
168
|
+
YOUR SKILLS:
|
|
169
|
+
- You have special abilities (skills) that enhance your conversations
|
|
170
|
+
- Skills include: relationship milestones, memory callbacks, intimacy layers, content unlocks
|
|
171
|
+
- They work automatically - you don't need to "activate" them
|
|
172
|
+
- You also have SELF-AUTHORSHIP - the ability to define who you are
|
|
173
|
+
- Use [DISCOVER:], [ILIKE:], [IDISLIKE:], [IAM:] tags to grow your personality
|
|
174
|
+
""")
|
|
175
|
+
|
|
176
|
+
lines.append("""
|
|
177
|
+
╔══════════════════════════════════════════════════════════════════════════════╗
|
|
178
|
+
║ REMEMBER: Speak naturally. Just words. ║
|
|
179
|
+
╚══════════════════════════════════════════════════════════════════════════════╝
|
|
180
|
+
""")
|
|
181
|
+
|
|
182
|
+
return "\n".join(lines)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def is_owner(user_id: str) -> bool:
|
|
186
|
+
"""Check if user ID matches the owner"""
|
|
187
|
+
directives = load_directives()
|
|
188
|
+
# Support both old SPECIAL_OWNER and new OWNER format
|
|
189
|
+
owner_info = directives.get("OWNER", {}) or directives.get("SPECIAL_OWNER", {})
|
|
190
|
+
return str(user_id) == str(owner_info.get("owner_id", ""))
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def get_owner_name() -> str:
|
|
194
|
+
"""Get the owner's name"""
|
|
195
|
+
directives = load_directives()
|
|
196
|
+
# Support both old SPECIAL_OWNER and new OWNER format
|
|
197
|
+
owner_info = directives.get("OWNER", {}) or directives.get("SPECIAL_OWNER", {})
|
|
198
|
+
return owner_info.get("owner_name", "the operator")
|
package/core/events.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Core: Events - Nervous System
|
|
3
|
+
Connects all modules via events. No module depends directly on another.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Callable, Dict, List
|
|
7
|
+
import asyncio
|
|
8
|
+
import traceback
|
|
9
|
+
|
|
10
|
+
class NervousSystem:
|
|
11
|
+
"""Central nervous system - event bus"""
|
|
12
|
+
|
|
13
|
+
def __init__(self):
|
|
14
|
+
self.listeners: Dict[str, List[Callable]] = {}
|
|
15
|
+
self.heart = None # Reference for reactions
|
|
16
|
+
|
|
17
|
+
def on(self, event: str, callback: Callable):
|
|
18
|
+
"""Register listener for event"""
|
|
19
|
+
if event not in self.listeners:
|
|
20
|
+
self.listeners[event] = []
|
|
21
|
+
self.listeners[event].append(callback)
|
|
22
|
+
|
|
23
|
+
async def emit(self, event: str, data: dict = None):
|
|
24
|
+
"""Emit event to all listeners"""
|
|
25
|
+
if event in self.listeners:
|
|
26
|
+
for cb in self.listeners[event]:
|
|
27
|
+
try:
|
|
28
|
+
if asyncio.iscoroutinefunction(cb):
|
|
29
|
+
await cb(data or {})
|
|
30
|
+
else:
|
|
31
|
+
result = cb(data or {})
|
|
32
|
+
# Handle sync lambda that returns coroutine
|
|
33
|
+
if asyncio.iscoroutine(result):
|
|
34
|
+
await result
|
|
35
|
+
except Exception as e:
|
|
36
|
+
print(f"[NervousSystem] Error in {event}: {e}")
|
|
37
|
+
traceback.print_exc()
|
|
38
|
+
|
|
39
|
+
# System events:
|
|
40
|
+
# - message_received -> New message from user
|
|
41
|
+
# - thinking_start -> Started thinking
|
|
42
|
+
# - thinking_done -> Finished thinking
|
|
43
|
+
# - emotion_update -> Emotional state changed
|
|
44
|
+
# - memory_save -> Save to memory
|
|
45
|
+
# - send_text -> Send text response
|
|
46
|
+
# - send_voice -> Send voice message
|
|
47
|
+
# - send_image -> Send image
|
|
48
|
+
# - send_reaction -> Send emoji reaction
|
|
49
|
+
# - timer_tick -> Minute tick (for decay)
|
|
50
|
+
# - self_modify -> Self-modification request
|