FIX: QVAC (QuantumVerse Automatic Computer) Packing
This commit is contained in:
+21
-4
@@ -41,22 +41,38 @@ Manual inputs: `skip_client`, `server_hosts`, `client_hosts`, `dry_run`.
|
||||
## Local parity
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm ci # includes @qvac/sdk for desktop LLM packaging
|
||||
SKIP_INTEGRATION=1 npm test
|
||||
|
||||
# Server (Linux Bare)
|
||||
npm run make:server:linux-x64
|
||||
|
||||
# Client (Electron)
|
||||
# Client (Electron) — ships QVAC Bare worker via @qvac/sdk/electron-forge
|
||||
npm run make:client:linux-x64
|
||||
|
||||
# Full matrix (slow)
|
||||
# Tools-only client (skip native QVAC worker / larger natives)
|
||||
PEARDATA_SKIP_QVAC=1 npm run make:client:linux-x64
|
||||
|
||||
# Full matrix (slow; QVAC raises client package time)
|
||||
npm run make
|
||||
|
||||
# Stage release archives without upload
|
||||
DRY_RUN=1 bash scripts/gitea-rolling-release.sh
|
||||
```
|
||||
|
||||
## QVAC in release clients
|
||||
|
||||
| Item | Detail |
|
||||
|------|--------|
|
||||
| Dependency | `@qvac/sdk` in `package.json` **dependencies** (must install under this repo — not a parent hoist) |
|
||||
| Forge plugin | `@qvac/sdk/electron-forge` + `@electron-forge/plugin-base` |
|
||||
| Config | `qvac.config.json` — LLM plugin only |
|
||||
| Asar | Forced **off** when QVAC packaging is enabled (Bare needs real paths) |
|
||||
| Skip | `PEARDATA_SKIP_QVAC=1` → tools-only client |
|
||||
| Docs | [QVAC.md](./QVAC.md) · [Electron tutorial](https://docs.qvac.tether.io/tutorials/electron) |
|
||||
|
||||
Client package default timeout is **20 minutes** when QVAC is enabled (`PEARDATA_CLIENT_TIMEOUT_MS`).
|
||||
|
||||
## Key scripts
|
||||
|
||||
| Script | Role |
|
||||
@@ -66,10 +82,11 @@ DRY_RUN=1 bash scripts/gitea-rolling-release.sh
|
||||
| `scripts/make.cjs` | Orchestrate server/client builds |
|
||||
| `scripts/bare-standalone.cjs` | Pack Bare `peardata-server` |
|
||||
| `scripts/build-client-bundle.cjs` | esbuild GUI → `electron/app.bundle.cjs` |
|
||||
| `scripts/build-qvac-worker.cjs` | Local `bundleSdk` for QVAC Bare worker |
|
||||
| `scripts/predownload-electron.cjs` | Pre-fetch Electron zips for CI |
|
||||
| `scripts/sign-macos-app.cjs` | Darwin client codesign |
|
||||
| `scripts/gitea-rolling-release.sh` | Build + stage + Gitea upload |
|
||||
| `forge.config.cjs` | Electron Forge packaging |
|
||||
| `forge.config.cjs` | Electron Forge + optional `QvacForgePlugin` |
|
||||
|
||||
## Integration tests in CI
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ The client shell is a **Pear desktop application** built with `pear-electron` +
|
||||
| `ui/dashboard.js` | Charts tab master metrics wall |
|
||||
| `ui/data-manager.js` | Settings → Data (retention / prune / storage usage) |
|
||||
| `ui/logs.js` | System Log tab (journal default for admins) |
|
||||
| `ui/qvac/*` | QVAC local AI tab (onboarding + tools; needs `@qvac/sdk` in this project) |
|
||||
| `shared/taxonomy.js` | Section grouping for the metrics wall |
|
||||
| `shared/container-names.js` | Human Docker/cgroup labels for the wall |
|
||||
| `shared/format.js` | Overview KPI unit scaling |
|
||||
|
||||
+108
-62
@@ -1,27 +1,117 @@
|
||||
# QVAC integration (local AI)
|
||||
|
||||
PearData’s **QVAC** tab is a local-first SRE copilot. Inference runs on the **desktop** (Electron/Pear); the agent only serves metrics over existing P2P RPC / REST. No cloud LLM is required.
|
||||
PearData’s **QVAC** tab is a local-first SRE copilot. Inference runs on the **desktop** (Electron / Pear); the agent only serves metrics over existing P2P RPC / REST. No cloud LLM is required.
|
||||
|
||||
Upstream: [tetherto/qvac](https://github.com/tetherto/qvac) · [docs.qvac.tether.io](https://docs.qvac.tether.io)
|
||||
Upstream: [tetherto/qvac](https://github.com/tetherto/qvac) · [docs.qvac.tether.io](https://docs.qvac.tether.io) · [Electron packaging tutorial](https://docs.qvac.tether.io/tutorials/electron)
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
Desktop QVAC tab
|
||||
→ ui/qvac (engine + tools + onboarding)
|
||||
→ @qvac/sdk (optional) OR tools-only fallback
|
||||
→ @qvac/sdk (+ Bare worker) OR tools-only fallback
|
||||
→ manager.request(Methods.*)
|
||||
→ PearMonitor agent
|
||||
```
|
||||
|
||||
| Layer | Responsibility |
|
||||
|-------|----------------|
|
||||
| Desktop | Model download/load, chat UI, tool loop |
|
||||
| Desktop | Model download/load, chat UI, tool loop, Bare worker |
|
||||
| Agent | Lean composite reads (`getHostSnapshot`, `searchCharts`, `summarizeChart`) + existing metrics RPCs |
|
||||
| REST | `/api/v3/ai/*` mirrors for scripts |
|
||||
|
||||
Agent overhead is unchanged when the QVAC tab is unused (no model load on the agent).
|
||||
|
||||
## Why `pear run` worked but CI releases did not
|
||||
|
||||
| Environment | How `@qvac/sdk` was resolved |
|
||||
|-------------|------------------------------|
|
||||
| **`pear run -d .` on a dev machine** | Often found a **hoisted** install (e.g. `~/node_modules/@qvac/sdk`) even when the project did not declare the dependency |
|
||||
| **CI Electron client** | Clean `npm ci` in the repo — **no `@qvac/sdk`**, no Bare worker entry, asar packing blocked natives |
|
||||
|
||||
CI / rolling releases only ship what is in **this** package’s `dependencies` + forge output. Dev must not rely on parent `node_modules`.
|
||||
|
||||
## Packaging (Electron / CI)
|
||||
|
||||
### Dependencies
|
||||
|
||||
```json
|
||||
"dependencies": {
|
||||
"@qvac/sdk": "^0.16.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@electron-forge/plugin-base": "^7.11.2"
|
||||
}
|
||||
```
|
||||
|
||||
`@electron-forge/plugin-base` is the peer for `@qvac/sdk/electron-forge`.
|
||||
|
||||
### Config
|
||||
|
||||
`qvac.config.json` lists **only** the plugins PearData needs (keeps the worker smaller):
|
||||
|
||||
```json
|
||||
{
|
||||
"plugins": ["@qvac/sdk/llamacpp-completion/plugin"]
|
||||
}
|
||||
```
|
||||
|
||||
### Forge plugin
|
||||
|
||||
`forge.config.cjs` loads `QvacForgePlugin` when the SDK is installed. On package it:
|
||||
|
||||
1. Runs `bundleSdk` + `verifyBundle` for the target `platform-arch`
|
||||
2. Forces **`asar: false`** (Bare cannot load `.bare` addons from asar)
|
||||
3. Tree-shakes unused `@qvac/*` addons and prunes foreign prebuilds
|
||||
|
||||
Official caveats: [Electron tutorial → packaging](https://docs.qvac.tether.io/tutorials/electron#step-4-package-for-distribution).
|
||||
|
||||
### Escape hatch
|
||||
|
||||
```bash
|
||||
PEARDATA_SKIP_QVAC=1 npm run make:client:linux-x64
|
||||
```
|
||||
|
||||
Produces a **tools-only** client (no LLM natives). QVAC tab still works via RPC tools.
|
||||
|
||||
### Local parity with CI
|
||||
|
||||
```bash
|
||||
npm ci # installs @qvac/sdk into THIS project
|
||||
npm run build:client-bundle
|
||||
npm run build:qvac-worker # optional local bare-pack
|
||||
npm run make:client:darwin-arm64 # or any host from scripts/hosts.cjs
|
||||
```
|
||||
|
||||
Increase client package timeout if needed: `PEARDATA_CLIENT_TIMEOUT_MS=1800000`.
|
||||
|
||||
### Runtime paths (packaged Electron)
|
||||
|
||||
`electron/main.cjs` sets `QVAC_WORKER_PATH` to the first existing:
|
||||
|
||||
- `app/qvac/worker.entry.mjs`
|
||||
- `app/qvac/worker.bundle.js`
|
||||
- `resources/qvac/...` / asar.unpacked variants
|
||||
|
||||
SDK also searches those locations itself ([node-rpc-client](https://github.com/tetherto/qvac)).
|
||||
|
||||
## Pear desktop
|
||||
|
||||
| Piece | Role |
|
||||
|-------|------|
|
||||
| `qvac/worker.pear.entry.mjs` | Bare worker entry (LLM plugin only) |
|
||||
| `package.json` → `pear.stage.entrypoints` | Stages the worker for pear |
|
||||
| `pear.pre` | Stays `pear-electron/pre` (single pipe owner) |
|
||||
|
||||
Install deps in the **project** (`npm i` / `npm ci`), not only in a parent folder:
|
||||
|
||||
```bash
|
||||
npm ci
|
||||
pear run -d .
|
||||
```
|
||||
|
||||
Optional combined pre (advanced): `scripts/pear-pre.mjs` — only if you understand pear-pipe ownership; default remains `pear-electron/pre`.
|
||||
|
||||
## Model profiles
|
||||
|
||||
| Profile | Chat constant | Tools | Typical use |
|
||||
@@ -31,17 +121,7 @@ Agent overhead is unchanged when the QVAC tab is unused (no model load on the ag
|
||||
| Strong | `QWEN3_4B_INST_Q4_K_M` | yes | ≥16 GB RAM |
|
||||
| Tool-tiny | `LLAMA_TOOL_CALLING_1B_INST_Q4_K` | yes | Fallback |
|
||||
|
||||
Embeddings (future RAG): `GTE_LARGE_FP16`.
|
||||
|
||||
## Install full local LLM
|
||||
|
||||
```bash
|
||||
npm i @qvac/sdk
|
||||
```
|
||||
|
||||
Without the SDK, the tab still works in **tools-only** mode: it calls agent RPCs and formats grounded answers (no generative model).
|
||||
|
||||
Onboarding lives in the QVAC tab (Setup). Preferences: `qvacOnboarded`, `qvacProfile`, `qvacMode` in desktop settings.
|
||||
Without the SDK (or if load fails), the tab stays in **tools-only** mode: live agent RPCs, no generative model.
|
||||
|
||||
## Agent RPCs (viewer)
|
||||
|
||||
@@ -51,65 +131,31 @@ Onboarding lives in the QVAC tab (Setup). Preferences: `qvacOnboarded`, `qvacPro
|
||||
| `searchCharts` | `{ q, limit }` catalog search |
|
||||
| `summarizeChart` | `{ chart, after?, points? }` min/avg/max/last per dim |
|
||||
|
||||
### REST
|
||||
|
||||
- `GET /api/v3/ai/snapshot`
|
||||
- `GET /api/v3/ai/charts?q=&limit=`
|
||||
- `GET /api/v3/ai/chart/:id/summary?after=&points=`
|
||||
REST: `GET /api/v3/ai/snapshot`, `/api/v3/ai/charts`, `/api/v3/ai/chart/:id/summary`.
|
||||
|
||||
## Tools the chat can call
|
||||
|
||||
| Tool | Purpose |
|
||||
|------|---------|
|
||||
| `host_snapshot` | Health + KPIs + anomalies |
|
||||
| `search_charts` / `summarize_chart` / `query_metric` | Catalog + series |
|
||||
| `list_anomalies` / `list_alerts` | Alerts surface |
|
||||
| `list_processes` | Process table |
|
||||
| `query_logs` | Journal / anomaly / audit |
|
||||
| `fleet_health` | Parent fleet summary |
|
||||
| `storage_info` | Retention + disk usage |
|
||||
| `local_knowledge` | Keyword RAG over guide + catalog (desktop) |
|
||||
| `open_chart` / `open_view` | UI navigation |
|
||||
| `silence_alert` | Operator + confirm dialog |
|
||||
|
||||
## Local knowledge (RAG)
|
||||
|
||||
Without embedding models, PearData uses **keyword retrieval** over:
|
||||
|
||||
- Built-in user-guide snippets (`ui/qvac/rag.js`)
|
||||
- Live chart catalog titles/contexts
|
||||
|
||||
Context is injected into the system prompt when **Settings → QVAC → Inject local knowledge** is on (default).
|
||||
`host_snapshot`, `search_charts`, `summarize_chart`, `query_metric`, `list_anomalies`, `list_alerts`, `list_processes`, `query_logs`, `fleet_health`, `storage_info`, `local_knowledge`, `open_chart`, `open_view`, `silence_alert` (operator + confirm).
|
||||
|
||||
## Settings
|
||||
|
||||
| Pref | Default | Meaning |
|
||||
|------|---------|---------|
|
||||
| `qvacProfile` | recommended | Lite / Recommended / Strong / Tool-tiny |
|
||||
| `qvacRag` | true | Inject local knowledge |
|
||||
| `qvacIdleUnloadMin` | 30 | Unload model from RAM after idle minutes (0 = never) |
|
||||
| `qvacOnboarded` | false | Setup wizard completed |
|
||||
|
||||
## Desktop settings
|
||||
|
||||
| Key | Default | Meaning |
|
||||
|-----|---------|---------|
|
||||
| `qvacOnboarded` | `false` | Setup wizard completed |
|
||||
| `qvacProfile` | `recommended` | Model profile id |
|
||||
| `qvacMode` | `''` | `qvac` \| `fallback` after last load |
|
||||
| `qvacRag` | `true` | Inject guide + catalog snippets into prompts |
|
||||
| `qvacRag` | `true` | Inject guide + catalog snippets |
|
||||
| `qvacIdleUnloadMin` | `30` | Unload LLM after idle minutes (`0` = never) |
|
||||
|
||||
UI: **Settings → QVAC** and the QVAC tab header (Unload / Setup / New chat).
|
||||
|
||||
## Pear / Bare notes
|
||||
|
||||
- Electron: `@qvac/sdk` spawns a Bare worker automatically.
|
||||
- Pear: stub entry at `qvac/worker.pear.entry.mjs` (listed in `package.json` → `pear.stage.entrypoints`). Install `@qvac/bare-sdk` + `@qvac/llm-llamacpp` and uncomment plugin registration when enabling Pear-native inference.
|
||||
|
||||
## Related files
|
||||
|
||||
- `ui/qvac/*` — desktop UI + engine
|
||||
- `server/services/ai-tools.js` — composite reads
|
||||
- `shared/protocol.js` — method roles
|
||||
- `user-guide/qvac.md` — operator walkthrough
|
||||
| Path | Role |
|
||||
|------|------|
|
||||
| `ui/qvac/*` | Desktop UI + engine |
|
||||
| `qvac.config.json` | Plugin allow-list for bundling |
|
||||
| `qvac/worker.entry.mjs` | Electron/Node worker entry |
|
||||
| `qvac/worker.pear.entry.mjs` | Pear worker entry |
|
||||
| `forge.config.cjs` | `QvacForgePlugin` + ignore rules |
|
||||
| `scripts/build-qvac-worker.cjs` | Local `bundleSdk` |
|
||||
| `server/services/ai-tools.js` | Agent composite reads |
|
||||
| `user-guide/qvac.md` | Operator walkthrough |
|
||||
|
||||
@@ -54,8 +54,12 @@ Env knobs:
|
||||
| `PEARDATA_CLIENT_HOSTS` | all 64-bit | Client host list |
|
||||
| `PEARDATA_SKIP_CLIENT=1` | off | Server-only release |
|
||||
| `PEARDATA_SKIP_REBUILD=1` | on in CI | Skip `@electron/rebuild` |
|
||||
| `PEARDATA_SKIP_QVAC=1` | off | Tools-only Electron client (no Bare LLM worker) |
|
||||
| `PEARDATA_CLIENT_TIMEOUT_MS` | `1200000` with QVAC / `600000` without | Per-host client package timeout |
|
||||
| `DRY_RUN=1` | off | Stage archives, skip upload |
|
||||
|
||||
Desktop clients ship **QVAC** (`@qvac/sdk` + forge plugin) unless `PEARDATA_SKIP_QVAC=1`. See [QVAC.md](./QVAC.md) and [CI.md](./CI.md).
|
||||
|
||||
## CI / forge pipelines
|
||||
|
||||
| Forge | Workflow | Trigger | Output |
|
||||
|
||||
Reference in New Issue
Block a user