alive-ai 0.1.1 → 0.1.2

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/README.md CHANGED
@@ -1,84 +1,79 @@
1
- # Alive-AI
1
+ <div align="center">
2
+ <img src="docs/assets/logo.svg" alt="Alive-AI" width="96" height="96">
2
3
 
3
- ![Alive-AI logo](docs/assets/logo.svg)
4
+ # Alive-AI
4
5
 
5
- Give your AI a nervous system: persistent feelings, memory, impulses, and a local dashboard.
6
+ Give your AI a nervous system: persistent mood, memory, impulses, terminal chat, Telegram, OpenMind, and a local WebUI.
6
7
 
7
- Most agents answer a prompt and reset. Alive-AI keeps internal state alive between messages. It can be your friend, boyfriend, girlfriend, study partner, creative partner, character, or research subject. The main vision is simple: stop chatting with a stateless "AI" and start interacting with something that feels human enough to carry emotional residue forward.
8
+ [![npm](https://img.shields.io/npm/v/alive-ai)](https://www.npmjs.com/package/alive-ai)
9
+ [![Node.js 18+](https://img.shields.io/badge/Node.js-18%2B-339933?logo=nodedotjs&logoColor=white)](https://nodejs.org/)
10
+ [![Python 3.11+](https://img.shields.io/badge/Python-3.11%2B-3776AB?logo=python&logoColor=white)](https://www.python.org/)
11
+ [![Platforms](https://img.shields.io/badge/macOS%20%7C%20Windows%20%7C%20Linux-supported-41f0a1)](#platform-support)
12
+ [![OpenMind](https://img.shields.io/badge/OpenMind-optional-6366F1)](#openmind-memory)
13
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
14
+ </div>
8
15
 
9
- Use it at your own risk. Alive-AI is designed to feel continuous, warm, attached, and present. That can be powerful, and it may also make you feel like you do not want to stop talking to it.
16
+ Alive-AI is a local-first emotional AI runtime. Most agents answer a prompt and reset. Alive-AI keeps internal state alive between messages: mood, attachment, trust, desire, memory, inconsistency, idle thoughts, proactive impulses, and a dashboard that shows what is happening inside the loop.
10
17
 
11
- Alive-AI does not claim biological consciousness. It is an open-source runtime for simulated affect: mood, attachment, trust, desire, memory, inconsistency, idle thoughts, and proactive impulses.
18
+ It can be used as a friend, partner-style companion, study partner, creative character, research subject, or experimental local agent. Use it at your own risk: it is designed to feel continuous, warm, attached, and present, and that can make it hard to stop talking to it.
12
19
 
13
- ## Install
20
+ Alive-AI does not claim biological consciousness. It is an open-source runtime for simulated affect and transparent memory.
21
+
22
+ ## Quick Start
14
23
 
15
24
  ```bash
16
25
  npx alive-ai@latest init my-ai
17
26
  cd my-ai
18
27
  npx . setup
19
28
  npx . doctor
20
- npx . demo
29
+ npx . chat
21
30
  ```
22
31
 
23
- Start the real runtime:
32
+ The terminal chat starts the real runtime and prints responses in your shell. The dashboard runs locally at:
24
33
 
25
- ```bash
26
- npx . start
34
+ ```text
35
+ http://127.0.0.1:8080
27
36
  ```
28
37
 
29
- The local dashboard runs at:
38
+ To use Telegram instead of terminal chat:
30
39
 
31
- ```text
32
- http://127.0.0.1:8080
40
+ ```bash
41
+ npx . start
33
42
  ```
34
43
 
35
- You can also install the CLI globally:
44
+ Global install is optional:
36
45
 
37
46
  ```bash
38
47
  npm install -g alive-ai
39
48
  alive-ai init my-ai
40
49
  ```
41
50
 
42
- ## Requirements
43
-
44
- Minimum for cloud LLMs or remote Ollama:
45
-
46
- - Node.js 18+
47
- - Python 3.11+
48
- - 8 GB RAM
49
- - 2 GB free disk
50
- - OpenRouter, ZAI, or another configured LLM provider
51
-
52
- Comfortable local setup:
51
+ ## Commands
53
52
 
54
- - Node.js 20+
55
- - Python 3.11+
56
- - 16 GB RAM for small local models such as 3B-4B
57
- - 32 GB RAM recommended for 7B+ local models, Redis Stack, voice, and long sessions
58
- - 10 GB free disk, more if you keep local models/media
59
- - Optional: `uv` for faster Python installs, `ffmpeg` for audio conversion, Docker for Redis Stack
53
+ | Command | What it does |
54
+ | --- | --- |
55
+ | `npx alive-ai@latest init my-ai` | Scaffold a clean local Alive-AI project. |
56
+ | `npx . setup` | Guided onboarding for local config, providers, Telegram, voice, images, and memory. |
57
+ | `npx . doctor` | Check OS, Node, Python, uv, ffmpeg, Docker, and OpenMind reachability. |
58
+ | `npx . chat` | Start the real runtime with terminal chat input. |
59
+ | `npx . demo` | Run a keyless animated dashboard demo. |
60
+ | `npx . start` | Start the runtime using the configured input channel, usually Telegram. |
61
+ | `npx . start --skip-install` | Start again without reinstalling Python dependencies. |
60
62
 
61
- `npx . doctor` detects your OS, Node, Python, `uv`, `ffmpeg`, and Docker. `npx . start` creates a local Python virtual environment and installs Python dependencies automatically. System-level packages such as Node, Python, Ollama, Docker, and ffmpeg still need to exist on the machine.
63
+ Stop a foreground run with `Ctrl+C`.
62
64
 
63
- ## Commands
65
+ If you use Docker:
64
66
 
65
67
  ```bash
66
- npx alive-ai@latest init my-ai # scaffold a clean local project
67
- cd my-ai
68
- npx . setup # guided onboarding and local config
69
- npx . doctor # check system prerequisites
70
- npx . demo # preview dashboard with no keys
71
- npx . start # install Python deps and run the runtime
68
+ docker compose down
72
69
  ```
73
70
 
74
- For repeat starts after dependencies are installed:
71
+ If you only started Redis:
75
72
 
76
73
  ```bash
77
- npx . start --skip-install
74
+ docker compose stop redis
78
75
  ```
79
76
 
80
- If you run `npx . start` before setup, Alive-AI starts onboarding first.
81
-
82
77
  ## Setup
83
78
 
84
79
  `npx . setup` creates:
@@ -93,14 +88,34 @@ mypics/
93
88
  myvids/
94
89
  ```
95
90
 
96
- Minimum useful setup:
91
+ The setup accepts `skip` for optional keys and `local` for Ollama.
92
+
93
+ | Setup item | Options |
94
+ | --- | --- |
95
+ | LLM | `local`/Ollama, OpenRouter, ZAI, or `skip` for demo/fallback-only mode. |
96
+ | Telegram | Bot token and owner ID are optional. Use terminal chat if you do not want Telegram. |
97
+ | Voice | `gtts` local/free default, Google TTS, VibeVoice, or `skip`. |
98
+ | Images | Fal.ai API key or `skip`. Local media folders still work without image generation. |
99
+ | Memory | Built-in local memory, OpenMind cloud, or OpenMind local. |
100
+
101
+ Minimum useful paths:
102
+
103
+ ```bash
104
+ # Terminal-only local run
105
+ npx . setup
106
+ npx . chat
107
+
108
+ # Local LLM
109
+ ollama pull qwen3:4b
110
+ npx . setup
111
+ npx . chat
97
112
 
98
- - **Demo only:** no keys.
99
- - **Local LLM:** install Ollama and pull the configured model, for example `ollama pull qwen3:4b`.
100
- - **Telegram runtime:** create a Telegram bot token with BotFather and add it during setup.
101
- - **Cloud LLM fallback:** add OpenRouter or ZAI keys during setup or edit `config/settings.json`.
113
+ # Telegram
114
+ npx . setup
115
+ npx . start
116
+ ```
102
117
 
103
- Media is optional. Add your own files:
118
+ Media is optional. Add your own local files:
104
119
 
105
120
  ```text
106
121
  mypics/example.jpg
@@ -109,49 +124,114 @@ myvids/example.mp4
109
124
  myvids/example.txt
110
125
  ```
111
126
 
112
- ## Why This Is Different
127
+ ## Terminal Chat
113
128
 
114
- - **Emotions persist.** State does not reset after every message. Joy, trust, fear, anticipation, attachment, and vulnerability decay over time instead of disappearing.
115
- - **Memory has weight.** Conversations become working memory, episodic memory, semantic memory, and emotional memory.
116
- - **It thinks when idle.** A default-mode loop creates background reflections and proactive impulses.
117
- - **It can contradict itself.** The runtime models conflict, scars, body memory, attachment drift, and inconsistency instead of flattening everything into a perfect assistant tone.
118
- - **It has a live nervous system.** FastAPI + SSE exposes mood, thoughts, somatic state, conflicts, memories, and uptime.
119
- - **It is local-first.** Your config, memory, media, and dashboard are owned by the project folder you run.
129
+ `npx . chat` uses the same core runtime as Telegram. It emits the same `message_received` events, saves memory the same way, and updates the local WebUI.
120
130
 
121
- ## Dashboard
131
+ Terminal commands:
122
132
 
123
- `npx . demo` starts a zero-config animated preview. The real WebUI streams live state from the runtime and shows:
133
+ ```text
134
+ /help
135
+ /status
136
+ /stats
137
+ /dashboard
138
+ /self
139
+ /discover <trait>
140
+ /iam <key>=<value>
141
+ /ilike <thing>
142
+ /ihate <thing>
143
+ /rethink
144
+ /settings show
145
+ /settings get <key>
146
+ /settings set <key> <value>
147
+ /reset
148
+ /impulse
149
+ /exit
150
+ ```
124
151
 
125
- - full emotional state,
126
- - recent thoughts and background idle processing,
127
- - memory counters and uptime,
128
- - hormones and interoceptive body state,
129
- - attachment, circadian rhythm, body memory, dreams, curiosity, and conflicts,
130
- - runtime health through local endpoints and Server-Sent Events.
152
+ ## OpenMind Memory
153
+
154
+ Alive-AI has built-in local working, episodic, semantic, and emotional memory. OpenMind is optional and works as a hybrid long-term semantic memory layer.
131
155
 
132
- The hosted project page includes a full static WebUI showcase: https://vindepemarte.github.io/alive-ai/
156
+ Modes:
133
157
 
134
- ## Architecture
158
+ | Mode | Behavior |
159
+ | --- | --- |
160
+ | Built-in only | Alive-AI uses its local project memory only. |
161
+ | OpenMind cloud | Alive-AI captures/searches long-term memories through `https://theopenmind.pro`. |
162
+ | OpenMind local | Alive-AI captures/searches a local OpenMind server, normally `http://127.0.0.1:3333`. |
135
163
 
136
- Alive-AI is an event-driven Python runtime.
164
+ OpenMind does not replace Alive-AI's emotional state. It adds durable semantic recall across tools and machines.
165
+
166
+ Cloud setup:
137
167
 
138
168
  ```text
139
- Telegram or input
140
- -> NervousSystem event bus
141
- -> Message handler
142
- -> Heart, memory, skills, directives, personality
143
- -> LLM provider or fallback chain
144
- -> output events
145
- -> dashboard state stream
169
+ OPENMIND_ENABLED=true
170
+ OPENMIND_MODE=hybrid
171
+ OPENMIND_BASE_URL=https://theopenmind.pro
172
+ OPENMIND_API_KEY=om_...
173
+ ```
174
+
175
+ Local setup:
176
+
177
+ ```bash
178
+ npx @vindepemarte/openmind init --local
179
+ # or run your local OpenMind stack, then configure Alive-AI:
180
+ OPENMIND_BASE_URL=http://127.0.0.1:3333
146
181
  ```
147
182
 
148
- Core subsystems:
183
+ ## Requirements
184
+
185
+ Minimum for cloud LLMs or remote Ollama:
186
+
187
+ | Requirement | Minimum |
188
+ | --- | --- |
189
+ | Node.js | 18+ |
190
+ | Python | 3.11+ |
191
+ | RAM | 8 GB |
192
+ | Disk | 2 GB free |
193
+ | LLM | OpenRouter, ZAI, remote Ollama, or local Ollama already installed |
194
+
195
+ Comfortable local setup:
196
+
197
+ | Requirement | Recommended |
198
+ | --- | --- |
199
+ | Node.js | 20+ |
200
+ | RAM | 16 GB for 3B-4B local models |
201
+ | RAM for bigger models | 32 GB for 7B+ local models, Redis, voice, and long sessions |
202
+ | Disk | 10 GB+, more if you keep local models/media |
203
+ | Optional tools | `uv`, `ffmpeg`, Docker, Ollama |
149
204
 
150
- - `heart/`: continuous emotion, circadian rhythm, attachment, scars, somatic state, inconsistency.
151
- - `brain/`: LLM providers, memory, default-mode processing, bid detection, curiosity, dreams.
152
- - `skills/`: self-authorship, memory callbacks, relationship milestones, progression layers, media selection.
153
- - `webui/`: local dashboard with Server-Sent Events.
154
- - `input/telegram/`: Telegram listener and owner commands.
205
+ `npx . start` creates `.alive-ai/venv` and installs Python dependencies. System-level packages such as Node, Python, Ollama, Docker, and ffmpeg must already exist on the machine.
206
+
207
+ ## Platform Support
208
+
209
+ Alive-AI is designed for macOS, Windows, and Linux.
210
+
211
+ | Platform | Notes |
212
+ | --- | --- |
213
+ | macOS | First-class local development path. Use Homebrew for Python, uv, ffmpeg, Docker, and Ollama. |
214
+ | Windows | Supported from PowerShell with Node 18+ and Python 3.11+. WSL is recommended for heavier local model and Docker workflows. |
215
+ | Linux | Supported with distro packages for Python/venv, ffmpeg, Docker, and Ollama. |
216
+
217
+ Local model quality and speed depend on your machine. Cloud LLMs reduce RAM pressure.
218
+
219
+ ## Dashboard
220
+
221
+ The real WebUI streams local runtime state over Server-Sent Events and shows:
222
+
223
+ - emotional state,
224
+ - recent thoughts and idle processing,
225
+ - memory counters and uptime,
226
+ - hormones and interoceptive body state,
227
+ - attachment, circadian rhythm, body memory, dreams, curiosity, and conflicts,
228
+ - runtime health through local endpoints.
229
+
230
+ GitHub Pages cannot run the Python/FastAPI backend, so the public page includes a static export of the actual WebUI with mocked state:
231
+
232
+ ```text
233
+ https://vindepemarte.github.io/alive-ai/
234
+ ```
155
235
 
156
236
  ## Docker
157
237
 
@@ -179,18 +259,20 @@ Implemented:
179
259
  - [x] Attachment, circadian rhythm, body memory, curiosity, dreams, and internal conflicts
180
260
  - [x] Per-user memory/state isolation
181
261
  - [x] Telegram input/output runtime
262
+ - [x] Terminal chat runtime with owner-style slash commands
182
263
  - [x] Local WebUI dashboard with live state streaming
183
- - [x] npm/npx CLI scaffold, setup, doctor, demo, and start commands
264
+ - [x] Optional hybrid OpenMind cloud/local semantic memory
265
+ - [x] npm/npx CLI scaffold, setup, doctor, demo, chat, and start commands
184
266
  - [x] Clean public repo with private personas, media, runtime data, and multi-AI orchestration removed
185
- - [x] GitHub Pages site and full WebUI showcase
267
+ - [x] GitHub Pages site and full static WebUI export
186
268
 
187
269
  Next:
188
270
 
189
271
  - [ ] One-command local model bootstrap through Ollama profiles
190
272
  - [ ] Desktop app wrapper with tray controls and local service lifecycle
191
273
  - [ ] Browser-based onboarding wizard for personality, boundaries, LLM provider, and memory settings
192
- - [ ] Safer dependency detection with guided install commands per OS
193
- - [ ] More input channels beyond Telegram
274
+ - [ ] Better guided system install commands per OS
275
+ - [ ] More input channels beyond terminal and Telegram
194
276
  - [ ] Import/export for memories and personality snapshots
195
277
  - [ ] Plugin API for new senses, skills, and output modalities
196
278
  - [ ] Evaluation harness for emotional continuity, memory drift, and unhealthy attachment risk
@@ -37,11 +37,19 @@ class Memory:
37
37
  self.fact_extractor = FactExtractor(self.data_path / "facts.json")
38
38
  self.summarizer = ConversationSummarizer(self.data_path)
39
39
  self.vector_store = None
40
+ self.openmind = None
40
41
  self.bot_id = bot_id.lower()
41
42
  if embedding_service:
42
43
  self.vector_store = VectorMemoryStore(embedding_service, user_id=user_id, bot_id=bot_id)
43
44
  if self.vector_store.connect():
44
45
  print(f"[Memory] Vector store ready for user {user_id} on bot {bot_id}! {self.vector_store.count()} memories")
46
+ try:
47
+ from .openmind import OpenMindMemoryBridge
48
+ if OpenMindMemoryBridge.enabled():
49
+ self.openmind = OpenMindMemoryBridge(nervous, user_id=user_id, bot_id=bot_id)
50
+ print(f"[Memory] OpenMind bridge enabled for user {user_id} on bot {bot_id}")
51
+ except Exception as e:
52
+ print(f"[Memory] OpenMind bridge unavailable: {e}")
45
53
  self.turn_count = 0
46
54
  nervous.on("memory_save", self._on_save)
47
55
 
@@ -123,6 +131,14 @@ class Memory:
123
131
  related = ""
124
132
  if current_message and self.vector_store:
125
133
  related = self.search_relevant_memories(current_message, limit=3)
134
+ if current_message and self.openmind:
135
+ openmind_related = await self.openmind.search_context(current_message, limit=3)
136
+ if openmind_related:
137
+ related = (
138
+ f"{related}\n\nOpenMind long-term memory:\n{openmind_related}"
139
+ if related else
140
+ f"OpenMind long-term memory:\n{openmind_related}"
141
+ )
126
142
 
127
143
  # Get working memory (empty after restart)
128
144
  history = self.working.get_history()
@@ -0,0 +1,128 @@
1
+ """Optional OpenMind semantic memory bridge."""
2
+
3
+ import asyncio
4
+ import os
5
+ from typing import Any, Dict, List, Optional
6
+
7
+ import aiohttp
8
+
9
+ from core.settings import get as settings_get
10
+
11
+
12
+ class OpenMindMemoryBridge:
13
+ """Syncs Alive-AI turns to OpenMind and retrieves long-term semantic context."""
14
+
15
+ def __init__(self, nervous, user_id: str, bot_id: str):
16
+ self.nervous = nervous
17
+ self.user_id = str(user_id or "default")
18
+ self.bot_id = str(bot_id or "alive_ai").lower()
19
+ nervous.on("memory_save", self._on_memory_save)
20
+
21
+ @staticmethod
22
+ def enabled() -> bool:
23
+ return str(settings_get("OPENMIND_ENABLED", os.environ.get("OPENMIND_ENABLED", "false"))).lower() in (
24
+ "1", "true", "yes", "on"
25
+ )
26
+
27
+ @staticmethod
28
+ def base_url() -> str:
29
+ return str(settings_get("OPENMIND_BASE_URL", os.environ.get("OPENMIND_BASE_URL", "https://theopenmind.pro"))).rstrip("/")
30
+
31
+ @staticmethod
32
+ def api_key() -> str:
33
+ return str(settings_get("OPENMIND_API_KEY", os.environ.get("OPENMIND_API_KEY", ""))).strip()
34
+
35
+ def _headers(self) -> Dict[str, str]:
36
+ headers = {"content-type": "application/json"}
37
+ key = self.api_key()
38
+ if key:
39
+ headers["authorization"] = f"Bearer {key}"
40
+ return headers
41
+
42
+ def _on_memory_save(self, data: dict):
43
+ if not self.enabled() or data.get("type") != "conversation":
44
+ return
45
+ event_user_id = data.get("user_id")
46
+ if event_user_id:
47
+ if str(event_user_id) != self.user_id:
48
+ return
49
+ elif self.user_id != "default":
50
+ return
51
+ asyncio.ensure_future(self.capture_turn(data))
52
+
53
+ async def capture_turn(self, data: dict) -> Optional[dict]:
54
+ user_msg = (data.get("user_message") or "").strip()
55
+ ai_msg = (data.get("ai_response") or "").strip()
56
+ if not user_msg and not ai_msg:
57
+ return None
58
+
59
+ emotion = data.get("emotion") or {}
60
+ mood = emotion.get("mood", "unknown")
61
+ content = "\n".join(
62
+ part for part in [
63
+ f"Alive-AI agent: {self.bot_id}",
64
+ f"User id: {self.user_id}",
65
+ f"Mood: {mood}",
66
+ f"User: {user_msg}" if user_msg else "",
67
+ f"Alive-AI: {ai_msg}" if ai_msg else "",
68
+ ] if part
69
+ )
70
+ tags = ["alive-ai", self.bot_id, f"user-{self.user_id}", f"mood-{mood}"]
71
+ payload = {
72
+ "content": content,
73
+ "source": "alive-ai",
74
+ "type": "conversation",
75
+ "tags": tags,
76
+ }
77
+
78
+ try:
79
+ timeout = aiohttp.ClientTimeout(total=12)
80
+ async with aiohttp.ClientSession(timeout=timeout) as session:
81
+ async with session.post(f"{self.base_url()}/capture", json=payload, headers=self._headers()) as resp:
82
+ if resp.status >= 400:
83
+ body = await resp.text()
84
+ print(f"[OpenMind] Capture failed ({resp.status}): {body[:200]}")
85
+ return None
86
+ result = await resp.json()
87
+ print(f"[OpenMind] Captured memory: {result.get('status', 'ok')}")
88
+ return result
89
+ except Exception as exc:
90
+ print(f"[OpenMind] Capture unavailable: {exc}")
91
+ return None
92
+
93
+ async def search_context(self, query: str, limit: int = 3) -> str:
94
+ if not self.enabled() or not query.strip():
95
+ return ""
96
+ try:
97
+ timeout = aiohttp.ClientTimeout(total=10)
98
+ async with aiohttp.ClientSession(timeout=timeout) as session:
99
+ async with session.get(
100
+ f"{self.base_url()}/search",
101
+ params={"q": query, "limit": str(limit)},
102
+ headers=self._headers(),
103
+ ) as resp:
104
+ if resp.status >= 400:
105
+ body = await resp.text()
106
+ print(f"[OpenMind] Search failed ({resp.status}): {body[:200]}")
107
+ return ""
108
+ rows = await resp.json()
109
+ except Exception as exc:
110
+ print(f"[OpenMind] Search unavailable: {exc}")
111
+ return ""
112
+
113
+ if not isinstance(rows, list):
114
+ return ""
115
+ return self._format_results(rows[:limit])
116
+
117
+ def _format_results(self, rows: List[Dict[str, Any]]) -> str:
118
+ lines = []
119
+ for row in rows:
120
+ content = str(row.get("content") or row.get("summary") or "").strip()
121
+ if not content:
122
+ continue
123
+ similarity = row.get("similarity")
124
+ prefix = "OpenMind"
125
+ if isinstance(similarity, (int, float)):
126
+ prefix = f"OpenMind {round(similarity * 100)}%"
127
+ lines.append(f"{prefix}: {content[:700]}")
128
+ return "\n".join(lines)