updated documentation
This commit is contained in:
@@ -27,33 +27,46 @@ npm run dev # local dev server on port 5173
|
||||
Vite bakes environment variables into the bundle at build time. The `.env`
|
||||
file is only needed on the machine running the build, not where files are served.
|
||||
|
||||
After building, copy `dist/` contents to `/srv/nexusai` on Mini PC 2 for Caddy to serve.
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Required | Default | Description |
|
||||
|---|---|---|---|
|
||||
| VITE_ORCHESTRATION_URL | No | `''` (empty) | Orchestration base URL. Empty string uses Vite proxy in dev, Caddy proxy in production. |
|
||||
| VITE_ORCHESTRATION_URL | No | `''` (empty) | Orchestration base URL. Must be set to the HTTPS domain in production to avoid mixed content errors. |
|
||||
|
||||
Production value:
|
||||
```
|
||||
VITE_ORCHESTRATION_URL=https://nexus.jellystorm.com
|
||||
```
|
||||
|
||||
## Internal Structure
|
||||
```
|
||||
src/
|
||||
├── api/
|
||||
│ └── orchestration.js # All fetch calls to the orchestration service
|
||||
│ └── orchestration.js # All fetch calls to the orchestration service
|
||||
├── config/
|
||||
│ └── constants.js # FALLBACK_MODELS, DEFAULT_MODEL, API_DEFAULTS
|
||||
├── hooks/
|
||||
│ ├── useSession.js # Session list, history loading, active session state
|
||||
│ └── useChat.js # Message sending, SSE streaming, message state
|
||||
│ ├── useSession.js # Session list, history loading, active session state
|
||||
│ ├── useChat.js # Message sending, SSE streaming, message state
|
||||
│ ├── useModels.js # Dynamic model list fetched from /models endpoint
|
||||
│ └── useContextMenu.js # Right-click context menu position and visibility
|
||||
├── components/
|
||||
│ ├── App.jsx # Root component — layout and shared state
|
||||
│ ├── SessionList.jsx # Left sidebar — session list and new chat button
|
||||
│ ├── ChatWindow.jsx # Centre panel — message thread and input bar
|
||||
│ ├── MessageBubble.jsx # Individual message bubble (user or assistant)
|
||||
│ └── InfoPanel.jsx # Right panel — model selector and session metadata
|
||||
├── index.css # Global reset and CSS variables
|
||||
└── main.jsx # React entry point
|
||||
│ ├── App.jsx # Root component — layout and shared state
|
||||
│ ├── SessionList.jsx # Left sidebar — session list, rename, delete
|
||||
│ ├── ChatWindow.jsx # Centre panel — message thread and input bar
|
||||
│ ├── MessageBubble.jsx # Individual message bubble (user or assistant)
|
||||
│ ├── InfoPanel.jsx # Right panel — model selector and session metadata
|
||||
│ └── SessionModal.jsx # Modal dialog for session settings (rename)
|
||||
├── index.css # Global reset, CSS variables, utility classes
|
||||
└── main.jsx # React entry point
|
||||
```
|
||||
|
||||
## Layout
|
||||
|
||||
Three-panel layout with collapsible sidebars:
|
||||
```
|
||||
┌─────────────────┬──────────────────────────┬─────────────┐
|
||||
│ Session List │ Chat Window │ Info Panel │
|
||||
│ (collapsible) │ │ (collapsible)│
|
||||
@@ -64,9 +77,54 @@ Three-panel layout with collapsible sidebars:
|
||||
│ Session 2 │ │ │
|
||||
│ │ [input bar] │ │
|
||||
└─────────────────┴──────────────────────────┴─────────────┘
|
||||
```
|
||||
|
||||
On mobile, sidebars collapse to a 56px icon rail. The centre chat window
|
||||
always fills the remaining space.
|
||||
Sidebars collapse to a 56px icon rail. The centre chat window always
|
||||
fills the remaining space.
|
||||
|
||||
## CSS Architecture
|
||||
|
||||
Styles follow a hybrid approach — CSS utility classes for static reusable
|
||||
rules, inline styles for dynamic prop-driven values.
|
||||
|
||||
### CSS Variables (`:root`)
|
||||
|
||||
| Variable | Value | Description |
|
||||
|---|---|---|
|
||||
| `--bg-base` | `#0f1117` | Page background |
|
||||
| `--bg-surface` | `#1a1d27` | Panel backgrounds |
|
||||
| `--bg-elevated` | `#222536` | Elevated elements (inputs, cards) |
|
||||
| `--border` | `#2e3150` | Border colour |
|
||||
| `--accent` | `#6c63ff` | Primary accent (buttons, highlights) |
|
||||
| `--accent-hover` | `#574fd6` | Accent hover state |
|
||||
| `--text-primary` | `#e8e8f0` | Primary text |
|
||||
| `--text-secondary` | `#8b8fa8` | Secondary text |
|
||||
| `--text-muted` | `#555870` | Muted / placeholder text |
|
||||
| `--bubble-user` | `#6c63ff` | User message bubble background |
|
||||
| `--bubble-ai` | `#222536` | AI message bubble background |
|
||||
| `--sidebar-width` | `280px` | Expanded sidebar width |
|
||||
| `--panel-width` | `260px` | Expanded info panel width |
|
||||
| `--header-height` | `56px` | Shared header height across all panels |
|
||||
| `--radius-sm` | `6px` | Small border radius |
|
||||
| `--radius-md` | `8px` | Medium border radius |
|
||||
| `--radius-lg` | `12px` | Large border radius |
|
||||
|
||||
### Utility Classes
|
||||
|
||||
| Class | Description |
|
||||
|---|---|
|
||||
| `.panel-header` | Shared header row — used in all three panels |
|
||||
| `.btn-reset` | Resets button styles (no border, bg, cursor pointer) |
|
||||
| `.btn-icon` | Icon button with hover state |
|
||||
| `.btn-primary` | Accent-coloured action button with `:hover` and `:disabled` states |
|
||||
| `.flex` / `.flex-col` | Flex layout helpers |
|
||||
| `.flex-1` / `.flex-shrink` | Flex sizing helpers |
|
||||
| `.items-center` / `.justify-center` / `.justify-between` | Alignment helpers |
|
||||
| `.overflow-hidden` / `.scroll-y` | Overflow helpers |
|
||||
| `.text-xs` / `.text-sm` / `.text-base` | Font size helpers |
|
||||
| `.text-muted` / `.text-secondary` / `.text-accent` | Colour helpers |
|
||||
| `.label-upper` | Uppercase section label style |
|
||||
| `.truncate` | Text overflow ellipsis |
|
||||
|
||||
## API Layer
|
||||
|
||||
@@ -78,39 +136,71 @@ All orchestration calls are centralised in `src/api/orchestration.js`:
|
||||
| `fetchSessionHistory` | GET | /sessions/:id/history | Load episode history on session select |
|
||||
| `sendMessage` | POST | /chat | Send message, await full response |
|
||||
| `streamMessage` | POST | /chat/stream | Send message, receive SSE token stream |
|
||||
| `fetchModels` | GET | /models | Load available models from manifest |
|
||||
| `renameSession` | PATCH | /sessions/:id | Rename a session |
|
||||
| `deleteSession` | DELETE | /sessions/:id | Delete a session |
|
||||
|
||||
`streamMessage` returns an abort function — call it to cancel a stream mid-flight.
|
||||
It uses a buffer pattern to handle SSE chunks that may span multiple network packets.
|
||||
Uses a buffer pattern to handle SSE chunks that may span multiple network packets.
|
||||
|
||||
## Streaming
|
||||
|
||||
The chat input sends messages via `POST /chat/stream`. Tokens arrive as SSE events:
|
||||
```
|
||||
data: {"text":"Hello"}
|
||||
data: {"text":" Tim"}
|
||||
data: {"done":true}
|
||||
data: {"done":true,"model":"gemma-4-26B-A4B-Claude-Distill-APEX-I-Mini.gguf","tokenCount":87}
|
||||
```
|
||||
|
||||
An empty assistant bubble is appended immediately when the stream opens, then
|
||||
updated token by token using `updateLastMessage`. The blinking cursor in
|
||||
`MessageBubble` is shown while `message.streaming === true` and disappears
|
||||
when `done` is received.
|
||||
when the done event is received. Model name and token count from the done
|
||||
event are stored in `useChat` state and displayed in the InfoPanel.
|
||||
|
||||
## Model Selector
|
||||
## Dynamic Model Selector
|
||||
|
||||
Available models are defined in `InfoPanel.jsx`:
|
||||
Available models are fetched from `GET /models` on mount via the `useModels` hook.
|
||||
The hook initialises with `FALLBACK_MODELS` from `constants.js` and replaces them
|
||||
with the server response on success. If the fetch fails, the fallback list is used
|
||||
silently — a warning is logged to the console.
|
||||
|
||||
| Label | Value |
|
||||
|---|---|
|
||||
| Companion | `companion:latest` |
|
||||
| Mistral Nemo | `mistral-nemo:latest` |
|
||||
| Coder | `coder:latest` |
|
||||
| Qwen 2.5 Coder 14B | `qwen2.5-coder:14b` |
|
||||
```js
|
||||
// constants.js
|
||||
export const FALLBACK_MODELS = [
|
||||
{ value: 'companion:latest', label: 'Companion' },
|
||||
// ...
|
||||
];
|
||||
```
|
||||
|
||||
The selected model is passed with every chat request. To add a new model,
|
||||
update the `MODELS` array in `InfoPanel.jsx`.
|
||||
The selected model is passed with every chat request. To add a model, update
|
||||
`models.json` on the main PC — no client rebuild needed.
|
||||
|
||||
## Session Management
|
||||
|
||||
Sessions are identified by a `external_id` — a human-readable string or UUID
|
||||
generated client-side. New sessions are created locally with `uuid` and auto-registered
|
||||
in the memory service on the first message. The session list refreshes after each
|
||||
completed response to surface newly created sessions.
|
||||
Sessions are identified by `external_id` — a UUID generated client-side via the
|
||||
`uuid` package. New sessions are created locally and auto-registered in the memory
|
||||
service on the first message. The session list refreshes after each completed
|
||||
response to surface newly created sessions.
|
||||
|
||||
### Session Actions
|
||||
|
||||
The session list supports rename and delete:
|
||||
|
||||
- **Hover** — reveals ✎ (rename) and ✕ (delete) icon buttons on the session row
|
||||
- **Right-click** — opens a context menu with the same actions
|
||||
|
||||
Rename opens a `SessionModal` dialog. The modal is designed to expand into a full
|
||||
session settings panel in future — the title is already "Session Settings" to
|
||||
reflect this intent.
|
||||
|
||||
Delete is immediate with no confirmation dialog (planned for a future update).
|
||||
|
||||
Actions are disabled on unsaved (new) sessions that haven't had a message sent yet.
|
||||
|
||||
### Context Menu
|
||||
|
||||
Implemented via `useContextMenu` hook — tracks `{ x, y, session }` state and
|
||||
attaches a `window` click listener to dismiss on any outside click. Rendered
|
||||
outside the sidebar div (via React fragment) to avoid being clipped by
|
||||
`overflow: hidden`.
|
||||
Reference in New Issue
Block a user