Repository navigation
Conversation
Ayshinko
force-pushed
the
feature/gui-manager
branch
2 times, most recently
from
October 2, 2026 12:22
804e7ac to
98a4074
Compare
…ision, Low RAM, custom GGUF, Start/Stop/Restart)
A thin management GUI on top of setup.py and the existing strata-*.json configs: model/config
discovery uses setup.choices_from_config, edits write the same config format setup writes (atomic
writes + .bak backups), and Start launches the same serve/server.py command the generated run-*.bat /
run-*.sh scripts use. No engine code, no setup logic, and no downloads are duplicated.
gui/manager.py - HTTP server (127.0.0.1), config editor backend, folder picker
gui/launcher.py - platform-neutral supervisor (state, port checks, status, log tail)
gui/platforms/ - the only OS-specific code: spawn/terminate adapters (windows.py, linux.py)
gui/web/* - dependency-free dark UI using the Strata design tokens
START-MANAGER.bat, start-manager.sh - launchers (same code)
docs/GUI_MANAGER.md - what it is, launch, relation to START-HERE/SETUP, config storage,
Windows and Linux usage, limitations
gui/test_manager.py - 33 unit + HTTP round-trip tests (temp folders only; fake platform adapter
so the suite runs identically on Windows and Linux)
Vision/context/low-ram reuse setup.py's exact semantics and functions (derived_factor/resolve_rope,
low_ram_resident, VISION). Custom GGUF preparation delegates to the existing setup.py --gguf-dir
pipeline. Stop closes the process tree on Windows and SIGTERMs the server's group on Linux.
…e Stop The extra blank terminal was the engine: on Windows a console-subsystem child (strata.exe) spawned by a process with no console gets a brand-new visible console window. The Windows launcher now spawns the server with CREATE_NEW_CONSOLE and a console hidden from birth (STARTUPINFO SW_HIDE), so the engine inherits the hidden console instead of opening its own - verified on the real install (window snapshot: no new console window). The Manager's own console, and Linux behavior, are unchanged. Stop/Restart no longer look frozen: - backend lifecycle states stopped/starting/running/stopping/restarting/error, carried in logs/manager.json while an operation runs; /api/status reports the real phase (graceful/forcing/... ) and measured elapsed seconds - UI switches to Stopping/Restarting immediately on click (never waits for the API), shows a spinner + 'Gracefully shutting down the engine 4.2s' ticking locally, and confirms 'Stopped in Xs' - Restart walks Stopping -> Starting -> Running visibly - new Force Stop button (POST /api/force-stop) terminates the process tree immediately; normal Stop still tries graceful shutdown first - fixed the Windows PID-alive check (os.kill(pid,0) kept reporting dead processes as alive, which made every stop burn its full grace wait): OpenProcess + GetExitCodeProcess now answers immediately - a normal stop went from ~30 s to ~3 s - measured: normal stop 3.26 s (forced fallback after ~3 s), restart 4.7 s to running, force stop 0.1 s; port 8080 released and VRAM back to 1.2-1.4 GiB after each stop
…y proxy, external detection, console-free launcher The Manager becomes a first-class page of ONE Strata web app (Manager / Chat / Monitor / About) served by the persistent control server on 127.0.0.1:8275 - no iframe, no second tab, no redirect to 8080, no page reload on Start/Restart. - gui/web/index.html + app.css: the Manager view rebuilt native in the Strata UI kit (tokens.css/components.css), as a fourth tab next to Chat/Monitor/About. - gui/web/app.js: a thin shell that loads serve/web/app.js unchanged and adds the Manager tab, hash navigation (default #manager, remembered), offline awareness (clean 'Strata is not running' states; Chat/Monitor/About resume automatically) and the lifecycle/external pills. serve/web/app.js is reused verbatim under web/serve-app.js - no copied, diverging frontend. - gui/manager.py: serves the shared UI kit + fonts and proxies Strata's own endpoints (/health /metrics /mcp /settings /v1/* ...) on the SAME origin, with the config's API key injected and the browser Origin kept off the wire (no CORS hacks); streams Chat SSE; answers a clean 'offline' 503 while Strata is down. - gui/launcher.py: 'external' state - a Strata started outside the Manager is detected by its configured port answering the real /v1/models endpoint (with the config's key), never by a random process on the port; Start/Stop/Restart refuse to touch it, and the status returns to Stopped automatically. - START-MANAGER.bat: launches with pythonw.exe through 'start' - no console window at all (the browser page is the control center); output/logs to logs/manager.log; gui/manager.py prints tolerate pythonw (stdout is None). - serve/web/sprite.svg: one new i-manager glyph (additive). - gui/test_manager.py: 7 new tests - external detection (incl. key-protected and not-strata cases), the gateway (proxied metrics/models/chat-stream, offline 503, Manager UI alive), unified page file serving. 59->43 manager tests: 43 pass; serve server/detok/lifecycle/winjob/monitor/ structured/mcp: 143 pass (7 skipped: need engine/GPU).
…nal detection Two Windows/Linux issues found while validating the unified Manager: 1. START-MANAGER.bat: replaced the parenthesized IF block (whose ECHO of a ')' string once produced the real ' . was unexpected at this time.' cmd failure) with a goto structure, and dropped the 'start ... >> log 2>&1' redirect. Under pythonw (sys.stdout is None) the redirected handle only LOCKED logs/manager.log for the Manager's whole lifetime without ever writing it; the Manager now writes its own startup/error lines there (gui/manager.py _out() falls back to the log file when there is no console). Verified from cmd.exe and PowerShell, and from a working directory outside the repo. 2. External Strata detection is now Strata-specific: a process on the configured port is only classified as external Strata when GET /api/health answers 200 JSON with service == 'strata' (the config's API key is sent when set). An OpenAI-compatible server (LM Studio, plain llama.cpp) that answers /v1/models with object/data has no Strata identity and is never claimed; /v1/models remains a readiness check only. A dead Manager PID with a non-Strata process on the port now falls through to the crash report instead of being mislabeled external. tests: +2 bat-structure checks, +4 detection checks (OpenAI-compatible server not detected, key-protected Strata detected with the configured key, Manager-owned server precedence, external disappearance -> Stopped). gui 50/50, serve 143 (7 engine/GPU-skipped), setup rope 19/19. Validated on the real machine with the installed Q2_0 model: start via Manager (Starting -> Running in ~18 s), Monitor metrics through the 8275 gateway (real GPU/VRAM/RAM), a real question streamed back through 8275, Restart (restarting -> running in 6 s, page stays alive), Stop (page stays alive with clean offline states), external instance via run-q2_0.bat-style launch detected as Running · External (~1 s) with Chat/Monitor working and Stop/Start refused, and the external instance's closing returning the status to Stopped.
…ccupies the fallback port 8080
…lished model of the same size The Manager identified a custom GGUF folder only by family+size (its tag), so a different build of the same size (Qwen3.8-Flash-Next Q2_0 Abliterated next to the original Q2_0) was "already installed" the moment strata-q2_0.json existed - and Prepare only flashed and returned. Fixes the identity, the naming, the setup.py integration and the UX: - identity is the GGUF files themselves: prepare first compares the chosen shards against every strata-*.json's --native/--ple-gguf; an existing config with the exact same files is selected, nothing runs - setup.py --variant LABEL: the existing pipeline, one extra flag. tag = size-variant, so the variant gets its OWN config (strata-q2_0-abliterated.json), its own pack (the fused Q2_0 experts are rebuilt from THIS build's shards, never the original's), its own log and run script - the canonical strata-q2_0.json is never written or touched - choices_from_config reads the variant from the config file name (split_size_variant), so an installed variant config loads with its family/size/variant and a human title - the Manager derives the variant label deterministically from the GGUF file/folder names, slugified filesystem-safe; a same-named but different build gets a short sha256 suffix IN the --variant, so setup.py writes exactly the collision-free name - UX: Prepare disables itself with "Preparing…", a card shows setup.py's live log, on success the model list refreshes, the NEW config is selected and a success toast names it; a failed run shows setup.py's error and the log path instead of silently flashing tests: original+same files -> already; original+different Q2_0 -> second unique config; two custom variants coexist; the original config is byte-identical after every prepare; names deterministic/safe; setup.py writes the variant config/pack/script and never the canonical config; prepare-status exposes failed/ready for the UI settle.
Ayshinko
force-pushed
the
feature/gui-manager
branch
from
October 3, 2026 09:58
98a4074 to
b6a87f4
Compare
…prepare a stale detection
The real import bug (E:\Model\Q2_0-Abliterated next to the original Q2_0):
- typing/pasting into the Custom GGUF field ran no detection at all, and the autofill on
model-select filled the field without one - so the visible path could be A while the
committed detection (and therefore Prepare) referred to folder B. Prepare then ran B
and answered "already installed as strata-q2_0.json", the original's config.
- detection kept its own shard regex and a MODELS substring scan instead of setup.py's
naming rules.
Now:
- the text field is the ONLY path ever detected or prepared. Every change (typed, pasted,
autofilled, Browse's "Use this folder") invalidates the previous detection immediately
and hides Prepare; the new value is detected through one code path, with a generation
token that drops late responses for an older value, and a successful detection is
committed only when its directory is exactly the current field value (ggufDet.accept).
Browse's preview panel never touches the committed state - "Use this folder" writes the
choice into the field and runs the same change handler, so browse and manual input can
not diverge. Prepare refuses (and re-detects) unless ggufDet.prepareAllowed - visible
path A + internal detection B is impossible.
- setup.py's own naming rules are the single source of truth: the shard set is its
SHARD_NAME pattern and the size is its GGUF_QUANT first, with a boundary-safe MODELS
scan as fallback (IQ2_0 inside a name can no longer match Q2_0); the detected directory
is resolved so "already installed" compares the canonical files (E:\Model\Q2_0-Abliterated
stays a different model from E:\Model\Q2_0 and never reuses the original's config).
Tests: node tests for the field state machine (stale invalidation, late response dropped,
Prepare refuses a mismatched detection, browse == manual input; gui/web/test_gguf_state.mjs,
run by the unittest suite when node is present), plus backend tests for the real abliterated
pattern, the quant boundary rules and canonical dirs. Verified end-to-end on the real
folder: detect returns family qwen / Q2_0 / abliterated, prepare builds its own pack and
writes strata-q2_0-abliterated.json (original strata-q2_0.json byte-identical), and both
models are listed with the variant selected.
…shes from the Manager Variant API identity: setup.py wrote model_name without the --variant label, so strata-q2_0-abliterated.json advertised qwen3.8-flash-next-q2_0 even though the Abliterated build was what the engine ran. A variant config now advertises qwen3.8-flash-next-q2_0-abliterated (api_identity: canonical name + '-' + the normalized label) and keeps the canonical name as an alias, so clients that still send the published id are answered while /v1/models, /v1/status and /api/health truthfully report what is loaded. Aliases the owner edited by hand survive a setup run again (saved_aliases). Canonical naming is unchanged. Black console flashes: the Manager runs under pythonw (no console), so its short utility subprocesses - nvidia-smi (manager system_info + setup.gpus and setup.cpu_info's powershell, all through setup.out/run), and taskkill (platforms/windows terminate/terminate_force) - each spawned a transient visible console. setup.child_flags() now returns CREATE_NO_WINDOW exactly when the current process has no console (the pythonw context); interactive terminal runs and Manager-spawned setup children (which have a hidden console to inherit) keep their exact behavior; Linux is untouched. The Manager's own nvidia-smi carries the same flags; taskkill always uses CREATE_NO_WINDOW; the long-lived server/engine hidden inherited console is preserved. Tests: tools/test_setup_identity (canonical/variant identity, saved_aliases, child_flags policy incl. a no-console simulation and the Linux zero), serve/test_identity (variant identity over real HTTP /v1/models + /v1/status from a config written as setup writes it), gui.test_manager NoWindowPolicy (system_info flags, taskkill CREATE_NO_WINDOW, engine spawn keeps its hidden console).
Owner
|
Thanks for the work and the clear write-up. We are not merging it as it stands, because the Manager opens three ways in that Strata's own server closes on purpose.
A version we could take needs:
With those, and a test for each (a foreign Origin, a text/plain POST, a wrong Host, a missing token), we would look again. The CREATE_NO_WINDOW part for the Windows launch is welcome as its own small PR. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds an optional Strata Manager that turns the existing Strata web UI into a unified local control surface:
Manager · Chat · Monitor · About
The Manager runs as a persistent local control server on 127.0.0.1:8275, while the normal Strata model server remains on its
existing port (usually 8080).
This keeps model configuration and lifecycle controls available even while Strata itself is stopped or restarting, without changing
the existing START-HERE / SETUP workflows.
What it adds
The new Manager tab supports:
Configuration continues to use the existing setup.py semantics and the same strata-*.json files. The Manager does not introduce a
second configuration system.
Unified web UI
The existing Strata frontend is reused rather than embedded as a separate site.
The result is one native interface: