Files
peardata/docs/QVAC.md
T
Raven Scott 2007ff6ad3
CI / test (push) Successful in 2m40s
Release rolling / release (push) Successful in 11m42s
Fix QVAC Worker
2026-07-30 16:01:34 -04:00

8.4 KiB
Raw Blame History

QVAC integration (local AI)

PearDatas 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 · docs.qvac.tether.io · Electron packaging tutorial

Architecture

Desktop QVAC tab
  → ui/qvac (engine + tools + onboarding)
  → @qvac/sdk (+ Bare worker)  OR  tools-only fallback
  → manager.request(Methods.*)
  → PearMonitor agent
Layer Responsibility
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 packages dependencies + forge output. Dev must not rely on parent node_modules.

Packaging (Electron / CI)

Dependencies

"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):

{
  "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.

Escape hatch

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.

Bare runtime binary

QVAC spawns a Bare worker via bare-runtime + a platform package such as bare-runtime-darwin-arm64.

These are listed under optionalDependencies (os/cpu-filtered). On a Linux CI runner npm ci will not install the darwin/win32 packages, so packaging must force-install them first (see scripts/ensure-qvac-bare-runtimes.cjs and CI.md).

Forge keeps bare-runtime + bare-runtime-<targetHost> in the app and fails the build if the binary is missing when QVAC packaging is enabled.

If you still see:

Could not load the Bare runtime binary for darwin-arm64
… bare-runtime-darwin-arm64 … missing

on a local or CI client:

npm ci
npm run ensure:qvac-bare-runtimes   # force-install all QVAC host binaries
npm run make:client:darwin-arm64

Worker RPC timeout (RPC initialization timed out after 30000ms)

bundleSdk writes absolute file:///build-machine/... imports into qvac/worker.entry.mjs. Off the build host Bare cannot load them, so the worker never handshakes.

Fix (already wired into forge + build-qvac-worker):

node scripts/rewrite-qvac-worker-entry.cjs --force-portable

That rewrites the entry to relative ../node_modules/@qvac/sdk/... imports so the packaged app is self-contained.

Native host matrix (LLM prebuilds)

@qvac/llm-llamacpp ships Bare prebuilds for:

Host Full QVAC Notes
linux-x64 yes
linux-arm64 yes
darwin-x64 yes CPU-oriented
darwin-arm64 yes Metal
win32-x64 yes Vulkan / CPU
win32-arm64 no No published prebuild — CI packages tools-only automatically

scripts/make.cjs and forge.config.cjs set PEARDATA_SKIP_QVAC=1 for unsupported hosts so the release matrix still emits a client zip.

Local parity with CI

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).

Pear desktop

Piece Role
qvac/worker.pear.entry.mjs Bare worker entry (LLM plugin only)
package.jsonpear.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:

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
Lite QWEN3_600M_INST_Q4 limited ≤8 GB RAM
Recommended QWEN3_1_7B_INST_Q4 yes Default
Strong QWEN3_4B_INST_Q4_K_M yes ≥16 GB RAM
Tool-tiny LLAMA_TOOL_CALLING_1B_INST_Q4_K yes Fallback

Without the SDK (or if load fails), the tab stays in tools-only mode: live agent RPCs, no generative model.

Agent RPCs (viewer)

Method Purpose
getHostSnapshot Health + KPIs + anomalies/alerts + catalog/storage summary
investigateHost One-shot diagnosis pack: findings, hot charts, top processes
hotMetrics Charts with strongest recent change / anomaly signal
relatedCharts Related charts for a seed id (catalog + weights)
compareChartWindows Baseline vs highlight window comparison on one chart
summarizeCharts Batch summarize up to 12 charts
searchCharts { q, limit } catalog search
summarizeChart { chart, after?, points? } min/avg/max/last per dim

REST: GET /api/v3/ai/snapshot, /api/v3/ai/investigate, /api/v3/ai/hot, /api/v3/ai/related, /api/v3/ai/compare, /api/v3/ai/summarize, /api/v3/ai/charts, /api/v3/ai/chart/:id/summary.

Tools the chat can call

Tools are tiered so small models stay within context:

Tier When Tools
core All tool-enabled profiles investigate_host, host_snapshot, search_charts, summarize_chart, list_anomalies, list_alerts, list_processes, local_knowledge, open_chart, open_view
deep Recommended / Strong hot_metrics, related_charts, compare_chart_windows, summarize_charts, query_metric, get_weights, query_logs, fleet_health, list_child_peers, storage_info, agent_health, node_info, db_info, list_contexts, get_chart, list_jobs, get_alert
write Operator role + confirm silence_alert, ack_alert, run_job

On context overflow the engine first drops to core tools, then drops tool schemas entirely and retries.

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
qvacIdleUnloadMin 30 Unload LLM after idle minutes (0 = never)
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