New: VisionPsy-Nano, a 460M vision model that outperforms models twice its size.
QVAC Logo

JS/TS SDK

Install and use the JavaScript/TypeScript client for QVAC.

Overview

The JS/TS SDK (@qvac/sdk on npm) is the JavaScript/TypeScript client for QVAC. It drives a Bare worker over bare-rpc, and exposes every QVAC capability through a unified, type-safe API.

Requirements

  • Node.js >= v22.17
  • npm >= v10.9
  • Bare >= v1.24 (if targeting Bare)
  • Expo >= v54 (if targeting mobile)

For host-level requirements (OS versions, GPU drivers, Vulkan runtime), see System requirements.

Install

npm i @qvac/sdk

Expo

Install peer dependencies:

npm i 'react-native-bare-kit@^0.11.5'
npm i -D 'bare-pack@^1.5.1'
npx expo install expo-file-system expo-build-properties expo-device

Tip: use npx expo install for all expo-* packages to ensure compatibility with your project's Expo SDK version.

Configure expo-build-properties and add @qvac/sdk/expo-plugin to the plugins array in your app.json:

app.json
{
  "expo": {
    "plugins": [
      ["expo-build-properties", { 
        "android": { "minSdkVersion": 29 } 
      }], 
      "@qvac/sdk/expo-plugin"
    ]
  }
}

Prebuild your project to generate the native files:

npx expo prebuild

Build and run it on a physical device:

npx expo run:ios --device
# or
npx expo run:android --device

Due to limitations with llamacpp, QVAC currently does not run on emulators. You must use a physical device.

Quickstart

Run your first example using the JS/TS SDK.

Create the examples workspace:

mkdir qvac-examples
cd qvac-examples
npm init -y && npm pkg set type=module

Install the SDK:

npm i @qvac/sdk

Save this config in your workspace to enable client and server logs during the run:

qvac.config.json
{
  "loggerLevel": "info",
  "loggerConsoleOutput": true,
  "httpDownloadConcurrency": 3,
  "httpConnectionTimeoutMs": 10000
}

Create the quickstart script:

quickstart.js
// The SDK prints no logs by default. To see its client and server logs, run with
// QVAC_CONFIG_PATH pointing at a config that sets "loggerConsoleOutput": true
// (see the Quickstart docs).
import { loadModel, LLAMA_3_2_1B_INST_Q4_0, completion, unloadModel } from '@qvac/sdk';
try {
    // Load a model into memory
    const modelId = await loadModel({
        modelSrc: LLAMA_3_2_1B_INST_Q4_0,
        onProgress: (p) => {
            const mb = (n) => (n / 1e6).toFixed(1);
            const line = `▸ Downloading ${p.percentage.toFixed(0)}% (${mb(p.downloaded)}/${mb(p.total)} MB)`;
            process.stderr.write(process.stderr.isTTY ? `\r${line}` : `${line}\n`);
            if (p.percentage >= 100)
                process.stderr.write('\n');
        }
    });
    // You can use the loaded model multiple times
    const history = [
        {
            role: 'user',
            content: 'Explain quantum computing in one sentence'
        }
    ];
    const result = completion({ modelId, history, stream: true });
    for await (const token of result.tokenStream) {
        process.stdout.write(token);
    }
    // Unload model to free up system resources
    await unloadModel({ modelId });
}
catch (error) {
    console.error('✖', error);
    process.exit(1);
}

Run the quickstart script:

QVAC_CONFIG_PATH=./qvac.config.json node quickstart.js

Or on Bare with @qvac/inference — see Running on Bare.

Running examples

Follow these instructions to run any example in this documentation:

  • All examples are self-contained, runnable JavaScript scripts. Use the qvac-examples workspace created in this quickstart to store and run them as you explore this documentation.
  • Run each example with the indicated compatible JavaScript environment. QVAC supports Node.js, Expo, and in-process Bare via @qvac/inference. The examples are written in Node style and run on Node.js or Bun directly; to run them on Bare, see Running on Bare.
  • More examples can be found in the SDK examples directory.
  • Some examples need companion files — sample audio, an image, or a config — that aren't part of the embedded code. These can be found in the same examples directory.
  • Some examples also provide a TypeScript version. If you want to run TS directly, install the required dev dependencies:
    npm i -D tsx typescript

Configuration

The SDK reads qvac.config.* from the project root, or from the path in QVAC_CONFIG_PATH:

QVAC_CONFIG_PATH=./qvac.config.json node app.js

See Configuration for options and schema.

File formats

The qvac.config.* format you can use depends on the JS environment where QVAC runs:

FormatNode.jsBareExpo
qvac.config.json
qvac.config.js
qvac.config.ts

qvac.config.ts requires installing tsx as a devDependency.

Supported on Node.js and Bare. Not supported in Expo — use JSON instead.

qvac.config.js
module.exports = {
  plugins: ["<builtin_plugin_1>", "<custom_plugin_2>"],
  loggerConsoleOutput: true,
  loggerLevel: "info",
  swarmRelays: ["<hyperbee_key_1>", "<hyperbee_key_2>"],
  cacheDirectory: "</absolute/path/to/.qvac/models>",
  httpDownloadConcurrency: 3,
  httpConnectionTimeoutMs: 10000,
  registryDownloadMaxRetries: 3,
  registryStreamTimeoutMs: 60000,
  rpcInitTimeoutMs: 30000,
  deviceDefaults: [
    {
      name: "Samsung Galaxy force CPU",
      match: { platform: "android", deviceBrand: "samsung" },
      defaults: { llm: { device: "cpu" } },
    },
  ],
  bareRuntimeVersion: "<x.y.z>",
  serve: {
    models: {
      "<model_alias>": {
        model: "<SDK_MODEL_CONSTANT>",
        default: true,
        preload: true,
        config: {},
      },
    },
  },
};

Running on Bare

To run an example on Bare:

  1. Provide a process global. Install bare-process and set it before using @qvac/inference:
    import process from "bare-process";
    globalThis.process = process;
  2. Register the plugins the example uses — Bare runs in-process and nothing auto-registers. See Runtime registration on Bare.

Here is the SDK quickstart adapted for Bare with @qvac/inference:

quickstart-adapted.ts
// The SDK's quickstart, adapted for Bare with @qvac/inference. Three edits: import
// from `@qvac/inference` instead of `@qvac/sdk`, import `process` from bare-process
// (Bare has no `process` global), and register the plugins this example uses
// via `plugins([...])`.

import process from 'bare-process'
import { plugins, LLAMA_3_2_1B_INST_Q4_0 } from '@qvac/inference'
import { llmPlugin } from '@qvac/inference/llamacpp-completion/plugin'

const { loadModel, completion, unloadModel } = plugins([llmPlugin])

// From here it is the same as the SDK's quickstart.
const modelId = await loadModel({ modelSrc: LLAMA_3_2_1B_INST_Q4_0 })

const history = [{ role: 'user', content: 'Explain quantum computing in one sentence' }]
const result = completion({ modelId, history, stream: true })
for await (const token of result.tokenStream) {
  process.stdout.write(token)
}

await unloadModel({ modelId, autoClose: true })

For running QVAC on Bare in production, use @qvac/inference — the Bare-only in-process engine. Select addons and register plugins explicitly. @qvac/bare-sdk is deprecated; last release is 0.18.2.

API reference

API reference

@qvac/sdk npm package exposes a function-centric, typed JS API.

On this page

Ask anything about QVAC.