# Chat Client **Package:** `@nexusai/chat-client` **Location:** `packages/chat-client` **Deployed on:** Mini PC 2 (192.168.0.205) **URL:** `https://nexus.jellystorm.com` (behind Authelia SSO) ## Purpose Browser-based chat interface for NexusAI. Communicates exclusively with the orchestration service — no direct access to memory, embedding, or inference services. Served as static files by Caddy on Mini PC 2. ## Dependencies - `react` + `react-dom` — UI framework - `uuid` — session ID generation - `vite` + `@vitejs/plugin-react` — build tooling ## Build ```bash cd packages/chat-client npm run build # outputs to dist/ 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. ## 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. | ## Internal Structure ``` src/ ├── api/ │ └── orchestration.js # All fetch calls to the orchestration service ├── hooks/ │ ├── useSession.js # Session list, history loading, active session state │ └── useChat.js # Message sending, SSE streaming, message state ├── 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 ``` ## Layout Three-panel layout with collapsible sidebars: ┌─────────────────┬──────────────────────────┬─────────────┐ │ Session List │ Chat Window │ Info Panel │ │ (collapsible) │ │ (collapsible)│ │ │ [message thread] │ │ │ + New Chat │ │ Model │ │ │ │ Session ID │ │ Session 1 │ │ Token count │ │ Session 2 │ │ │ │ │ [input bar] │ │ └─────────────────┴──────────────────────────┴─────────────┘ On mobile, sidebars collapse to a 56px icon rail. The centre chat window always fills the remaining space. ## API Layer All orchestration calls are centralised in `src/api/orchestration.js`: | Function | Method | Path | Description | |---|---|---|---| | `fetchSessions` | GET | /sessions | Load session list for sidebar | | `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 | `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. ## Streaming The chat input sends messages via `POST /chat/stream`. Tokens arrive as SSE events: data: {"text":"Hello"} data: {"text":" Tim"} data: {"done":true} 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. ## Model Selector Available models are defined in `InfoPanel.jsx`: | Label | Value | |---|---| | Companion | `companion:latest` | | Mistral Nemo | `mistral-nemo:latest` | | Coder | `coder:latest` | | Qwen 2.5 Coder 14B | `qwen2.5-coder:14b` | The selected model is passed with every chat request. To add a new model, update the `MODELS` array in `InfoPanel.jsx`. ## 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.