forked from enderofwings/NexusOS
Merge origin/main (v1.2.0: Projects, modules, in-app updates)
Reconciles 17 commits of this session's work (self-alteration tools, vendored Curry, slash-command dispatch, Windows toolchain/gate fixes) against origin/main's v1.2.0 sync (Projects/RAG scoping, a new modules/ system for mail and network, in-app updates, the standalone memory microservice folded into an in-process curator, KDE desktop theme overhaul). Nine real conflicts, each resolved by hand after reading both sides' actual diffs rather than picking one side wholesale: - synapse/tools.py, tests/test_tools.py: origin/main's diff here was small and clean (read_file/list_files, two new tests) despite git's diff3 flagging the whole file as one conflict blob -- reset to this branch's version and hand-spliced their addition in at the same points they used, rather than trying to reconcile a false 800-line conflict. Found and fixed a real bug while verifying: _list_files returned backslash-separated paths on Windows, which don't match the forward-slash glob patterns the tool's own schema documents. - synapse/main.py: kept this branch's cue-based standing advertisement of render_preview/run_snippet (independent of any playbook granting them) AND adopted origin/main's fix for routed reference playbooks not bringing their own tools along -- dropping either would have been a real regression, not just a style difference. Also: the standalone memory service (port 8001) is gone upstream, so its dead CORS/kill- target entries were removed; NEXUS_BACKEND_PORT parameterization and the manage_ollama-conditional kill logic (this branch's remote-Ollama support) were kept over origin/main's hardcoded equivalents. - synapse/memory/store.py: kept this branch's _delete_message_vectors helper (already reused elsewhere, batches to stay under SQLite's variable limit) over origin/main's inline duplicate of the same fix. - synapse/nexus_config.py, nexusos_cli/ncp.py: dropped the now-dead memory-service port/service entries; kept NEXUS_BACKEND_PORT env override and the manage_ollama-conditional kill-target list. - CLAUDE.md, README.md: merged both sides' additions, no real conflict. Found and fixed three more issues while independently verifying the merged tree, none of them mine or origin/main's alone -- only visible once both sides actually ran together: - modules/ (the new mail+network package) was never added to pyproject.toml's wheel `packages` list OR the sdist's `include` allowlist, so `from modules.registry import ROUTERS` in main.py would ImportError on any wheel install. Fixed both; bin/check.sh's packaging gate now asserts modules/ actually ships. tests/ test_packaging_deps.py's FIRST_PARTY/SHIPPED_PACKAGES sets were updated to recognize the new package. - tests/test_mail_creds.py's 0600-mode assertions are POSIX-only -- NTFS has no equivalent permission bits, so os.open(path, 0o600) on Windows just creates a normal file and stat.S_IMODE reports 0o666 regardless. Made the assertions platform-aware rather than skip real coverage (the temp-file-cleanup and password round-trip checks in the same test still run on Windows) or paper over a genuine OS limitation with a fake pass. - tests/test_kde_theme.py used bare Path.read_text() in fifteen places; Windows' default locale encoding (cp1252, not UTF-8) can't decode a real UTF-8 byte in the QML it reads, and did fail on one of the fifteen. Fixed all fifteen, not just the one that happened to trip today, since the other fourteen were equally fragile. Verified: full bin/check.sh reports OK end-to-end on this Windows checkout -- pytest (tests + management): 295 passed, 0 failed, 9 skipped; eslint clean; frontend node:test 57/57; PowerShell/shell parse clean; wheel + sdist pass twine check and now correctly carry modules/ (60 files, up from 52 pre-merge). synapse.main:app builds with 74 routes (up from 54 pre-merge, matching the new Projects/mail/ network endpoints).
This commit is contained in:
@@ -10,20 +10,32 @@ NexusOS is a local AI assistant platform. It runs a Python/FastAPI backend (Syna
|
||||
|
||||
NexusOS runs **single-process**: the Synapse backend on port 8000 serves the
|
||||
built web UI (`interface/web/dist`) itself, so there is no separate Vite server
|
||||
at runtime. Ollama is started manually (sidebar **Start AI** / `nexus-cli.sh
|
||||
start --ai`), not on backend startup.
|
||||
at runtime. Ollama is not started on backend process startup itself, but `ncp
|
||||
start`/`start -b` bring it up right after via the `/ollama/start` endpoint; the
|
||||
sidebar **Start/Stop AI** button and `ncp start --ai` remain for toggling it
|
||||
independently once the backend is already up.
|
||||
|
||||
**Windows (recommended):**
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File .\install-windows.ps1 # one-time native install
|
||||
ncp web # memory :8001 + backend :8000 + UI
|
||||
ncp web # backend :8000 + UI
|
||||
```
|
||||
`ncp` comes from `management\ncp.cmd`, which the installer puts on the machine
|
||||
PATH — open a NEW shell after installing. `.\launch_nexus.ps1` is what the
|
||||
desktop shortcut runs and still works directly.
|
||||
|
||||
**Linux install / update:**
|
||||
```bash
|
||||
./install.sh # wrapper over `python3 bin/sync.py restore`
|
||||
./install.sh --check # dry run
|
||||
./install.sh --no-desktop # skip the XFCE wiring (test clones, non-XFCE boxes)
|
||||
```
|
||||
|
||||
**Linux full stack (dev):**
|
||||
```bash
|
||||
./launch_nexus.sh
|
||||
```
|
||||
This activates the `Promethean` venv and starts the memory service on port 8001 and the Synapse backend on port 8000 (which also serves the built UI). It additionally starts a **Vite dev server** for frontend hot-reload — a Linux-dev convenience, unlike the single-process Windows/production path where the backend serves `dist/` alone. It does **not** start Ollama.
|
||||
This activates the `Promethean` venv and starts the Synapse backend on port 8000 (which also serves the built UI). It additionally starts a **Vite dev server** for frontend hot-reload — a Linux-dev convenience, unlike the single-process Windows/production path where the backend serves `dist/` alone. It does **not** start Ollama.
|
||||
|
||||
**macOS (community-supported):**
|
||||
```bash
|
||||
@@ -42,10 +54,7 @@ absent; that gets full Metal GPU acceleration with no extra config.
|
||||
source Promethean/bin/activate
|
||||
|
||||
# Backend (serves the built UI at :8000 too)
|
||||
uvicorn synapse.main:sio_app --host 0.0.0.0 --port 8000 --reload
|
||||
|
||||
# Memory service
|
||||
uvicorn synapse.memory.service:app --host 0.0.0.0 --port 8001 --reload
|
||||
uvicorn synapse.main:sio_app --host 127.0.0.1 --port 8000 --reload
|
||||
|
||||
# Frontend DEV server (hot-reload) — only when editing the UI; production is the
|
||||
# built dist/ served by the backend. Run `npm run build` to refresh dist/.
|
||||
@@ -97,13 +106,15 @@ cd interface/web && npm run build
|
||||
## Architecture
|
||||
|
||||
### Python venv
|
||||
All Python code runs inside `Promethean/` (a local venv). Always activate it before running backend commands: `source Promethean/bin/activate`. Dependencies are layered: `requirements-base.txt` holds the GPU-agnostic core, and a thin overlay pins the right PyTorch build for the target — `requirements-amd.txt` (ROCm), `requirements-nvidia.txt` (CUDA, generated by `bin/gen-nvidia-reqs.py`), or `requirements-windows.txt` (CPU-only). `bin/sync.py` (`requirements()`) selects NVIDIA, AMD, CPU/Windows, or — via an explicit `sys.platform == "darwin"` check, since `os.name` alone can't tell macOS apart from Linux — `requirements-base.txt` with no overlay at all for macOS, from the host.
|
||||
All Python code runs inside `Promethean/` (a local venv). Always activate it before running backend commands: `source Promethean/bin/activate`. Dependencies are layered: `requirements-base.txt` holds the GPU-agnostic core (nothing in it needs a GPU or imports torch), and a thin overlay per platform sets the right PyTorch package index — `requirements-amd.txt` (ROCm), `requirements-nvidia.txt` (CUDA, generated by `bin/gen-nvidia-reqs.py`), or `requirements-windows.txt` (CPU-only, standalone). `bin/sync.py` (`requirements()`) selects NVIDIA, AMD, CPU/Windows, or — via an explicit `sys.platform == "darwin"` check, since `os.name` alone can't tell macOS apart from Linux — `requirements-base.txt` with no overlay at all for macOS, from the host, and installs that alone by default — fast, no multi-GB downloads.
|
||||
|
||||
`requirements-ml.txt` is a separate, **opt-in** overlay for local ML inference (transformers/accelerate/bitsandbytes + torch/torchaudio/torchvision) — nothing in `synapse/` imports any of it; Ollama does all inference over HTTP. Only pull it in for local model work outside Ollama: `pip install -r requirements-amd.txt -r requirements-ml.txt` (or `-nvidia`, or alone for CPU-only torch). Not installed by `bin/sync.py`/the installers.
|
||||
|
||||
### Synapse Backend (`synapse/`)
|
||||
FastAPI app at `synapse/main.py`. Key responsibilities:
|
||||
- `/chat/stream` — chat with Ollama; streaming uses SSE (the only chat endpoint — the non-stream `/chat` was removed). After each exchange the stream endpoint calls the Memory Service to auto-extract persistent facts.
|
||||
- `/chat/stream` — chat with Ollama; streaming uses SSE (the only chat endpoint — the non-stream `/chat` was removed). When a conversation goes idle the stream endpoint hands it to the in-process curator, which extracts persistent facts.
|
||||
- `/playbooks` — CRUD for playbooks stored as YAML files in `data/playbooks/` via `synapse/playbooks/store.py`.
|
||||
- `/memory` — CRUD for persistent facts (proxies the same SQLite store as the memory service).
|
||||
- `/memory` — CRUD for persistent facts, backed by the same SQLite store the curator writes to.
|
||||
- `/models` — lists, pulls, and deletes Ollama models by proxying Ollama's HTTP API.
|
||||
- `/settings` and `/ollama` — persist runtime settings and control Ollama lifecycle.
|
||||
- `/conversations` — persists, retrieves, edits, deletes, and exports full chat history from SQLite.
|
||||
@@ -111,8 +122,8 @@ FastAPI app at `synapse/main.py`. Key responsibilities:
|
||||
|
||||
**System prompt assembly** (in `main.py` `chat_stream_endpoint`): the final system prompt is built by layering the active playbook instructions → reference playbook context → persistent memory facts → relevant past conversation snippets retrieved by `store.search_conversations`.
|
||||
|
||||
### Memory Service (`synapse/memory/`)
|
||||
A separate FastAPI app on port 8001. `service.py` exposes `/memories/extract` which calls `extractor.py` — an Ollama prompt that decides whether to persist a new fact from a conversation exchange. The main Synapse backend calls this asynchronously after each streaming response. Both services share the same SQLite database (`synapse/memory/memory.db`).
|
||||
### Memory (`synapse/memory/`)
|
||||
Runs **in-process** — there is no separate service and no second model. `curator.py` reads the messages a conversation has added since its watermark, `extractor.py` asks the chat model which permanent facts they contain, and `store.py` merges the results into `memory.db`. The backend schedules it when a conversation goes idle (`_pending_extractions` in `main.py`), so a half-said fact is never persisted mid-thought. The old :8001 FastAPI app held a second, smaller model that could not share the GPU with the chat model; the chat model is already resident, so the extra hop bought nothing.
|
||||
|
||||
### Playbook System (`synapse/playbooks/` + `synapse/playbook_manager.py`)
|
||||
Playbooks are ordered records (title, goal, instructions, tags), each persisted as a `{id}.yaml` file in `data/playbooks/` by `PlaybookFileStore` (the dir is `PLAYBOOK_DIR` in `nexus_config.py`). The **first** playbook by order is the active system prompt; all subsequent playbooks are injected as reference context. `PlaybookManager` is the thin class the backend uses to retrieve them and assemble the system prompt.
|
||||
@@ -171,3 +182,5 @@ A chat message that's nothing but `/tool_name(arg=val, ...)` (Python-call-shaped
|
||||
| Python dependencies (AMD/ROCm) | `requirements-amd.txt` |
|
||||
| Python dependencies (NVIDIA/CUDA) | `requirements-nvidia.txt` (generated by `bin/gen-nvidia-reqs.py`) |
|
||||
| Python dependencies (Windows/CPU) | `requirements-windows.txt` |
|
||||
| Python dependencies (optional local ML/torch) | `requirements-ml.txt` (opt-in, not installed by default) |
|
||||
|
||||
|
||||
Reference in New Issue
Block a user