Skip to content

Latest commit

 

History

240 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Eugene Plexus — ui

CI License: Apache 2.0 Next.js 16

Web UI for Eugene Plexus: a dashboard for the engine processes the supervisor runs, a schema-driven config editor for every component, and a chat playground over the gateway's OpenAI-compatible endpoint.

Status

Current through the M9 contracts (2026-09-11). Runtime dashboard, config editor, model library and profiles, discovery/downloads with hardware guidance, retained request metrics, and the playground are wired to the services. The UI generates all five API documents, including control, and proxies to the control root. /nodes is the first control-root screen — it mints a join token and renders the eugene-plexus-agent join command for the machine being added; the workflows past it are still blocked on whether the agent should own the UI at all.

A browser drives this now. npm run test:e2e runs Playwright against the system Chrome and a live install, covering first run, login, restart-on-login and the topology-resolved proxy — the arc jsdom cannot reach, because it has no layout, no navigation, no real fetch and no cookie jar. It is opt-in like every other acceptance run; CI still runs vitest. The first-run wizard is split one module per screen (src/app/setup/), and each screen can be mounted on its own; its screen list is still an open question. See the project status and the M9 acceptance record.

Pages

  • Playground (/) — pick a model from GET /v1/models and talk to it through POST /v1/chat/completions. Both are the gateway's OpenAI-compatible surface, unmodified: the playground deliberately uses no private path, because an endpoint only a first-party client can drive is not compatible with anything. A bar under the transcript reports which driver, runtime and backend served the turn, how long it took, and how many backends were tried — attempts > 1 is the visible evidence the failover cascade fired.

  • Runtimes (/runtimes) — the engine processes the agent supervises (GET /v1/runtimes) plus which engine adapters found a usable binary on this host (GET /v1/engines). Start / stop / restart per runtime, the resolved context length and slot count read back from the running engine, and the exact argv it was spawned with. loading is shown distinctly from starting, because a large quant off a slow disk sits there for minutes and that is not a fault.

  • Library (/library) - scanned GGUF and safetensors models, model details, named launch profiles, and launch through the agent.

  • Discover (/discover) - with nothing typed, the starter set: one card naming the model this machine should take, with the sentence that says why and a Download button, above the rest of the set. It renders with the hub down, because the endpoint behind it makes no upstream call. Typing searches; pasting a hub link resolves it to one repo and selects it. A repo opens with one suggested version and its own button above All versions, and every fit verdict names the context it was scored at (fits at 32k), with the control that changes it beside them. Model cards, download candidates, quant guidance against the selected node's hardware, and resumable download progress as before.

  • Config (/config) — reads /v1/config/schema from the selected component and renders a typed form. Component addresses come from agent topology. Driven by schema metadata, which is the point — a component that adds a knob gets a form field for free. PATCHes the diff back, surfaces applied / rejected / requiresRestart, and offers a Restart Now modal that polls /healthz until the component is back.

  • Metrics (/metrics) — what the gateway kept: per-request and per-attempt rows, latency and throughput by backend, and the tier each request was served from. Operator-only, and deliberately two rows per request rather than one, because a request total includes the attempts that failed.

  • Nodes (/nodes) — every machine in the install, its address, and whether the control root can reach it. Mints a single-use join token and renders the exact eugene-plexus-agent join command to paste on the machine being added. The other machine answers on its own terminal, because you cannot reach a worker's web UI until it advertises a non-loopback address, and setting that is part of what joining does.

  • First-run wizard (/setup) — five screens: welcome, passphrase + security mode, model directories, one external backend (optional), summary. It was eight until 2026-09-11; the three that went asked questions nothing answered — deployment topology and gateway address were collected, echoed back on the summary as if they were configuration, and never written by Start, and theme/font only ever touched localStorage and lives on /config. Split one module per screen under src/app/setup/, so a screen can be mounted and tested on its own. Auto-saves to sessionStorage; commits to the install on Start as a single transaction — which now includes enrolling this host's own agent with the control root it just spawned.

  • Same-origin proxy at /api/proxy/<target>/<...path> — the browser only talks to the origin it was served from; that origin forwards to the component URL. agent is this host's agent; gateway, library and control resolve from the agent's topology by kind, because an install has exactly one of each; anything else is an inference-driver by name. No CORS configuration on the components, no private URLs in the browser.

    The proxy is not in this repo any more. It moved into the agent (eugene_plexus_agent/routes/proxy.py) at install-paths §9 step 1, where resolving a target is an in-process lookup rather than an authenticated HTTP call back to the thing asking. Deleting it — the only dynamic route this application had — is what lets the UI ship as a static export inside a Python wheel, which takes Node out of the runtime on every platform.

Remaining Gaps

  • Control-root workflows: enrollment, rotation, promotion and topology management need dedicated screens; generated types and a proxy target are not those screens.
  • Structured model slots: model_slots currently renders as a JSON editor.
  • Runtime-name selection: the driver's runtime_name field remains free text.
  • Creating topology entries. The config editor and wizard configure components that already exist; adding one still means POST /v1/components or editing agent.yaml.

Running

In an install, this repo is not running at all. The agent serves the built assets at its own root (http://127.0.0.1:8079/ by default) out of the eugene-plexus-ui wheel. That is the path an operator takes and the path acceptance runs drive.

For development, with hot reload:

npm install
npm run codegen       # produces src/generated/*.ts from pinned specs
npm run dev           # http://localhost:3000

next dev is not the agent, so /api/proxy/... does not exist at that origin; a dev-only rewrites entry forwards it to the agent. Point it somewhere else with AGENT_URL:

AGENT_URL=http://agent.tailnet:8079 npm run dev

Component URLs are not configured here at all — not even the gateway's. The agent resolves every target from its own topology, which is also where the gateway reads it from, so one place records a component's URL and the UI and the router cannot disagree about where it is.

Packaging — eugene-plexus-ui

The browser half of an install is a Python distribution: a Next.js static export staged into python/eugene_plexus_ui/ and wrapped by hatchling, so pip install eugene-plexus-ui into the agent's interpreter is the whole of "add a browser". The agent finds it through importlib.resources and mounts it; without it the agent serves the API and says so at /.

npm run build:python                 # next build, then stage out/ into the package
python -m build --wheel              # dist/eugene_plexus_ui-*.whl

Two things that are easy to get wrong and are checked in CI: the export is only produced when NODE_ENV is production (output: "export" is conditional, because it cannot coexist with the dev rewrites), and the staged assets are gitignored build output, so hatchling has to be told to include them — a wheel without index.html installs and imports perfectly and is useless in a way only a browser notices.

Precedent for the shape: Open WebUI ships its built frontend inside its Python wheel.

Codegen

TypeScript types are generated from the pinned commit of eugene-plexus/specs recorded in SPECS_REF:

npm run codegen

The script downloads specs at the pinned SHA and runs openapi-typescript for agent, control, gateway, inference-driver, and library. Generated files (src/generated/*.ts) are committed; CI re-runs codegen and fails on diff. When introducing a spec document, update the codegen input list with the pin: a newer SPECS_REF alone does not cause a new document to be generated.

Development

npm install

npm run lint          # ESLint
npm run typecheck     # tsc --noEmit
npm run format:check  # Prettier
npm run build         # Next.js production build
npm run codegen       # Regenerate from pinned specs

License

Apache 2.0 — see LICENSE.

About

Web UI for Eugene Plexus: runtime dashboard, model library, discovery and downloads, schema-driven configuration, chat playground, and logs.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages