From e1375e7d1b487519aedc54b532de61588f75d98f Mon Sep 17 00:00:00 2001 From: Storme-bit Date: Sat, 18 Apr 2026 23:37:32 -0700 Subject: [PATCH] documentation update --- docs/reference/API-routes.md | 37 ++++-- docs/reference/Memory-isolation.md | 52 +++----- docs/services/chat-client.md | 119 ++++++++++++------ docs/services/memory-service.md | 31 +++-- .../src/components/ProjectView.jsx | 4 +- 5 files changed, 145 insertions(+), 98 deletions(-) diff --git a/docs/reference/API-routes.md b/docs/reference/API-routes.md index 7ed9e3b..af99925 100644 --- a/docs/reference/API-routes.md +++ b/docs/reference/API-routes.md @@ -32,8 +32,7 @@ here for reference and direct debugging use. ``` `model` and `temperature` are optional. Inference parameters (temperature, topP, topK, repeatPenalty) are read from `settings.json` on every request — -the request body values are not used for these; they are controlled via -`PATCH /settings`. +controlled via `PATCH /settings`. **POST /chat — response:** ```json @@ -91,7 +90,7 @@ Returns `{ sessionId, episodes: [...] }`. Episodes ordered newest first. |---|---|---| | GET | /projects | Get all projects | | POST | /projects | Create a new project | -| PATCH | /projects/:id | Update a project | +| PATCH | /projects/:id | Update a project (partial — any subset of fields) | | DELETE | /projects/:id | Delete a project (nulls session assignments) | **POST /projects — body:** @@ -101,13 +100,27 @@ Returns `{ sessionId, episodes: [...] }`. Episodes ordered newest first. "description": "Optional description", "colour": "#3d3a79", "icon": null, - "isolated": 0 + "isolated": 1 } ``` -`name` is required. All other fields optional. `isolated` is `0` or `1`. -Returns `201` with the created project object. +`name` is required. All other fields optional. `isolated` is always `1` — +all projects use isolated memory. Returns `201` with the created project object. -**PATCH /projects/:id — body:** same fields as POST, all optional. +**PATCH /projects/:id — body:** any subset of fields, all optional. + +| Field | Type | Description | +|---|---|---| +| `name` | string | Project name | +| `description` | string | Project description | +| `colour` | string | Hex colour for UI accent | +| `icon` | string | Icon identifier | +| `isolated` | integer | Memory isolation flag (always 1) | +| `notes` | string | User-authored project notes | + +Only provided fields are updated — omitted fields are not touched. This +enables safe partial updates (e.g. saving just `notes` without affecting +`name` or `colour`). Both orchestration and memory service implement dynamic +field patching. ### Models @@ -127,8 +140,9 @@ with `models.json` in the same folder for label and description metadata. ```json { "contextWindow": 64000, "modelAlias": "gemma-4-26B-A4B-Claude-Distill-APEX-I-Mini.gguf" } ``` -Fetches directly from llama-server `/props`. Returns `503` if llama-server -is unreachable. +Fetches directly from llama-server `/props`. `n_ctx` is at +`data.default_generation_settings.n_ctx` in the llama-server response. +Returns `503` if llama-server is unreachable. ### Settings @@ -218,8 +232,7 @@ orchestration. ```json { "name": "Session Name", "projectId": 3 } ``` -Both fields are optional. Only provided fields are updated — other fields -are not touched. +Both fields are optional. Only provided fields are updated. ### Episodes @@ -251,7 +264,7 @@ are not touched. | POST | /projects | Create a new project | | GET | /projects | Get all projects | | GET | /projects/:id | Get project by ID | -| PATCH | /projects/:id | Update a project | +| PATCH | /projects/:id | Update a project (dynamic — any subset of fields) | | DELETE | /projects/:id | Delete project + null session assignments | Same request/response shape as orchestration `/projects` above. diff --git a/docs/reference/Memory-isolation.md b/docs/reference/Memory-isolation.md index 3b2f1f4..24e49ac 100644 --- a/docs/reference/Memory-isolation.md +++ b/docs/reference/Memory-isolation.md @@ -1,15 +1,16 @@ # Memory Isolation NexusAI implements project-scoped memory — sessions belonging to the same -project can share semantic context, and isolated projects can be restricted -from drawing on memory outside the project. This document describes how the -system works end-to-end. +project share semantic context within that project's boundary. All projects +are isolated by default. ## Concepts **Session** — a single conversation thread. Identified by `external_id`. -**Project** — a named grouping of sessions. Has an `isolated` flag (0 or 1). +**Project** — a named grouping of sessions. `isolated` is always `1` — +the toggle has been removed from the UI and `isolated: 1` is hardcoded on +project creation. **Semantic search** — at inference time, the user's message is embedded and compared against past episodes in Qdrant to surface relevant context. The @@ -20,11 +21,10 @@ scope of this search is controlled by the project context. | Session state | Semantic search scope | |---|---| | No project | Own session's episodes only | -| Assigned to a non-isolated project | All episodes across all sessions in the project | -| Assigned to an isolated project | All episodes within the project only | +| Assigned to a project | All episodes across all sessions in that project | | Removed from a project | Own session's episodes only (from that point) | -Sessions with no project assigned behave the same as they always have — +Sessions with no project assigned behave as they always have — only their own past episodes are searched. ## How It Works @@ -44,16 +44,9 @@ if (session.project_id) { } ``` -If the session belongs to any project (isolated or not), `projectSessionIds` -is populated with the internal integer IDs of all sessions in that project. - -For **non-isolated projects**, this expands the search to all project sessions. -For **isolated projects**, the same set is used but the intent is restriction -— since `projectSessionIds` only contains project sessions, no external -episodes can appear. - -Both cases use the same code path — the `isolated` flag does not change the -query logic, only the conceptual meaning. +If the session belongs to any project, `projectSessionIds` is populated with +the internal integer IDs of all sessions in that project — creating a shared +memory pool across all conversations in the project. ### Step 2 — Qdrant filter construction @@ -96,26 +89,11 @@ message, `getProjectSessions` will not include that session's ID, so its episodes disappear from the semantic search scope. **New sessions created from ProjectView are assigned after the first message.** -The `useChat` hook writes the `project_id` assignment via `updateSession` after -`onDone` fires. There is a brief window during the first message where the -session has no project assigned. The project is correctly applied from the -second message onward. - -## Isolated vs Non-Isolated - -The `isolated` flag is stored on the project but does not currently change the -query logic — both isolated and non-isolated projects result in a -`projectSessionIds` filter. The distinction is semantic and enforced by -the project's membership: - -- **Non-isolated** — intentionally draws from all sessions in the project, - creating a shared memory pool for related conversations -- **Isolated** — by design contains only sessions explicitly added to it, - so the same filter naturally restricts context to project-only episodes - -If cross-project contamination became a concern (e.g. a session accidentally -added to the wrong project), removing it from the project immediately restores -isolation. +`handleNewProjectChat` in `App.jsx` calls `sendMessage` with the project ID, +which is passed to `useChat`. After `onDone` fires, `useChat` calls +`updateSession` to write the project assignment to the backend. There is a +brief window during the first message where the session has no project assigned. +The project is correctly applied from the second message onward. ## Qdrant Payload Structure diff --git a/docs/services/chat-client.md b/docs/services/chat-client.md index 0828926..8a144ae 100644 --- a/docs/services/chat-client.md +++ b/docs/services/chat-client.md @@ -82,7 +82,7 @@ src/ ├── api/ │ └── orchestration.js # All fetch calls to the orchestration service ├── config/ -│ └── constants.js # FALLBACK_MODELS, DEFAULT_MODEL, API_DEFAULTS +│ └── constants.js # FALLBACK_MODELS, DEFAULT_MODEL, API_DEFAULTS, CLIENT_DEFAULTS ├── hooks/ │ ├── useSession.js # Session list, history loading, active session state │ ├── useChat.js # Message sending, SSE streaming, message state @@ -93,14 +93,16 @@ src/ ├── components/ │ ├── App.jsx # Root component — layout, shared state, view routing │ ├── Sidebar.jsx # Left sidebar — projects, recent chats, navigation +│ ├── HomeView.jsx # Landing screen — greeting, centred input, quick actions │ ├── ChatWindow.jsx # Centre panel — message thread and input bar │ ├── MessageBubble.jsx # Individual message bubble — renders markdown via react-markdown │ ├── InfoPanel.jsx # Right panel — model selector and session metadata (slide-in) │ ├── SessionModal.jsx # Modal for session rename, project assignment, delete │ ├── ProjectModal.jsx # Modal for project create, edit, delete │ ├── AllChatsView.jsx # Full paginated session list with multi-select bulk delete -│ ├── AllProjectsView.jsx # Project tile grid with create/edit/delete -│ ├── ProjectView.jsx # Individual project — session list, new chat button +│ ├── AllProjectsView.jsx # Project tile grid with create/edit/delete; tile click navigates to ProjectView +│ ├── ProjectView.jsx # Individual project — conversations, new chat input, memory +│ │ # placeholder, user notes, ⋮ edit/delete menu │ ├── MemoryView.jsx # Paginated, searchable, expandable, deletable episode viewer │ └── SettingsView.jsx # Settings — Memory limits, Models (inference params, active │ # model, context window), Service Health, Appearance placeholder @@ -108,8 +110,6 @@ src/ └── main.jsx # React entry point ``` -> `SessionList.jsx` is superseded by `Sidebar.jsx` and kept only as a reference. - ## Layout The app uses a view-based layout. `App.jsx` manages a `view` state string @@ -120,13 +120,13 @@ panel are persistent across all views. ┌──────────────────┬──────────────────────────────┐ │ Sidebar │ Main Area (view-dependent) │ │ (collapsible) │ │ -│ │ chat → ChatWindow │ -│ + New Chat │ all-chats → AllChatsView │ -│ ⊞ View Projects │ all-projects → AllProjectsView│ -│ │ project → ProjectView │ -│ PROJECTS ▾ │ settings → SettingsView │ -│ [tile] [tile] │ memory → MemoryView │ -│ All Projects → │ │ +│ │ home → HomeView │ +│ + New Chat │ chat → ChatWindow │ +│ ⊞ View Projects │ all-chats → AllChatsView │ +│ │ all-projects → AllProjectsView│ +│ PROJECTS ▾ │ project → ProjectView │ +│ [tile] [tile] │ settings → SettingsView │ +│ All Projects → │ memory → MemoryView │ │ │ │ │ RECENT CHATS ▾ │ │ │ Session 1 │ │ @@ -137,24 +137,43 @@ panel are persistent across all views. └──────────────────┴──────────────────────────────┘ ``` -The sidebar collapses to a 48px icon rail. The right `InfoPanel` slides in -from the right using `transform: translateX()` — hidden by default, toggled -via the `⊹` button in the `ChatWindow` header. +The sidebar collapses to a 48px icon rail and starts collapsed on the home +view. The right `InfoPanel` slides in from the right using +`transform: translateX()` — hidden by default, toggled via the `⊹` button +in the `ChatWindow` header. ## View Routing | View | Component | Trigger | |---|---|---| -| `'chat'` | `ChatWindow` | Default; selecting a session; new chat | +| `'home'` | `HomeView` | Initial load; going back from chat with no history | +| `'chat'` | `ChatWindow` | Selecting a session; new chat; sending from HomeView | | `'all-chats'` | `AllChatsView` | "All Chats →" or ☰ icon in collapsed rail | | `'all-projects'` | `AllProjectsView` | "View Projects" button or ⊞ icon | -| `'project'` | `ProjectView` | Clicking a project tile in the sidebar | +| `'project'` | `ProjectView` | Clicking a project tile in sidebar or AllProjectsView | | `'settings'` | `SettingsView` | Settings button or ⚙ icon | | `'memory'` | `MemoryView` | "Open →" button in Settings → Memory section | `activeProject` state in `App.jsx` tracks which project `ProjectView` is displaying. Set via `onSelectProject` before navigating to `'project'`. +### View History Stack + +`App.jsx` maintains a `viewHistory` array. Each `navigate(view)` call pushes +the current view onto the stack. `goBack()` pops the last entry and restores +it. All view components receive `onBack={goBack}` — no component hardcodes +its own back destination. Navigating to `'home'` collapses the sidebar; +leaving `'home'` expands it. + +## Home View + +`HomeView` is the landing screen shown on initial load and when there are no +active sessions. It displays: +- Time-based greeting ("Morning / Afternoon / Evening, Tim") +- Currently loaded model name (from `modelProps.modelAlias`, stripped of `.gguf`) +- Centred textarea input — sending creates a new session and navigates to chat +- Quick action pills that populate the input without auto-sending + ## CSS Architecture Styles follow a hybrid approach — CSS utility classes for static reusable @@ -217,6 +236,10 @@ 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. +`useSession.selectSession` skips the history fetch for new (`isNew: true`) +sessions — fetching history for an unsaved session would 404 since it doesn't +exist in the backend yet. + ### Auto-naming After the first exchange completes, orchestration fires a secondary inference @@ -236,46 +259,60 @@ Session rows support rename, project assignment, and delete via: `SessionModal` handles rename and project assignment together in `settings` mode, and delete confirmation in `confirm-delete` mode. -### Active Session Clearing on Delete - -When the deleted session is the currently active one, `App.jsx` clears the -chat window before refreshing the list: - -```js -function handleSessionsChange(deletedSession) { - if (deletedSession?.external_id === activeSession?.external_id) { - selectSession(null); - } - refreshSessions(); -} -``` - ### Key Patterns - Button nesting: action icons are siblings of row buttons, not children — HTML forbids `