Releases: tetherto/qvac
Release list
QVAC SDK v0.15.0
📦 NPM: https://www.npmjs.com/package/@qvac/sdk/v/0.15.0
QVAC SDK 0.15.0 introduces single-job batch completion for running many prompts through one loaded model, adds LavaSR speech enhancement and denoising to the TTS pipeline, and extends Chatterbox TTS to Japanese and Chinese. It also gives multimodal models explicit GPU/CPU control over the vision encoder and ships stability fixes for Android worklets, worker RPC teardown, registry caching, and symlinked installs.
New APIs
Single-Job Batch Completion
batchCompletion runs many prompts through a single loaded model in one job, streaming per-prompt deltas and returning ordered results. Each prompt can carry its own history, generation parameters, and optional per-prompt tools or MCP-sourced tools.
import {
batchCompletion,
loadModel,
LLAMA_3_2_1B_INST_Q4_0,
} from "@qvac/sdk";
const modelId = await loadModel({
modelSrc: LLAMA_3_2_1B_INST_Q4_0,
modelType: "llm",
modelConfig: { ctx_size: 4096, parallel: 4 },
});
const run = batchCompletion({
modelId,
prompts: [
{
id: "a",
history: [{ role: "user", content: "Reply with only APPLE." }],
generationParams: { temp: 0, predict: 16 },
},
{
id: "b",
history: [{ role: "user", content: "What's the weather in Paris?" }],
tools: [getWeatherTool], // optional per-prompt tools
generationParams: { temp: 0, predict: 64 },
},
],
});
for await (const { id, event } of run.events) {
if (event.type === "contentDelta") process.stdout.write(`[${id}] ${event.text}`);
}
const results = await run.results; // ordered, all-or-nothing on stream-level failure
const stats = await run.stats; // batch-level CompletionStats | undefinedGPU Placement for Multimodal Vision Encoders
Multimodal LLMs can now force the vision encoder (mmproj) onto the GPU or CPU explicitly via the mmproj-use-gpu config key. Omit it to keep the previous per-device-class auto-selection.
await loadModel({
modelSrc: SMOLVLM2_500M_MULTIMODAL_Q8_0,
modelConfig: {
projectionModelSrc: MMPROJ_SMOLVLM2_500M_MULTIMODAL_Q8_0,
"mmproj-use-gpu": true, // true = GPU, false = CPU; omit to auto-select
},
});Features
LavaSR Speech Enhancement and Denoising for TTS
Supertonic TTS gains optional LavaSR post-processing: an enhancer and a denoiser that clean up generated audio. Both are opt-in via new load-time config keys, and Supertonic output can be resampled to a chosen rate.
await sdk.loadModel({
ttsEngine: "supertonic",
modelSrc: TTS_MULTILINGUAL_SUPERTONIC3_Q8_0.src,
// LavaSR post-processing (both optional)
lavasrDenoiserModelSrc: TTS_DENOISER_LAVASR_FP16.src,
lavasrEnhancerModelSrc: TTS_ENHANCER_LAVASR_FP16.src,
// Supertonic-only output sample rate (8000-192000 Hz)
outputSampleRate: 48000,
});Japanese and Chinese Chatterbox TTS
Chatterbox TTS now supports Japanese and Chinese. Japanese uses a MeCab IPADIC dictionary asset and Chinese uses a new Cangjie TSV asset, both passed at load time alongside the shared T3 and S3Gen models.
import {
loadModel,
TTS_T3_MULTILINGUAL_CHATTERBOX_Q4_0,
TTS_S3GEN_MULTILINGUAL_CHATTERBOX_Q4_0,
TTS_MECAB_IPADIC_CHATTERBOX,
TTS_CANGJIE_ZH_CHATTERBOX,
} from "@qvac/sdk";
// Japanese
await loadModel({
modelSrc: TTS_T3_MULTILINGUAL_CHATTERBOX_Q4_0,
modelConfig: {
ttsEngine: "chatterbox",
language: "ja",
s3genModelSrc: TTS_S3GEN_MULTILINGUAL_CHATTERBOX_Q4_0,
mecabDictSrc: TTS_MECAB_IPADIC_CHATTERBOX,
},
});
// Chinese
await loadModel({
modelSrc: TTS_T3_MULTILINGUAL_CHATTERBOX_Q4_0,
modelConfig: {
ttsEngine: "chatterbox",
language: "zh",
s3genModelSrc: TTS_S3GEN_MULTILINGUAL_CHATTERBOX_Q4_0,
cangjieTsvSrc: TTS_CANGJIE_ZH_CHATTERBOX,
},
});Bug Fixes
Android inference now always terminates the Bare worklet on teardown, preventing the worklet leak and out-of-memory growth seen under repeated model loads. When the bare-rpc channel closes, pending worker calls now surface as proper WorkerCrashedError / WorkerShutdownError instead of a generic RPC error, and the dead connection is torn down eagerly so the next call respawns cleanly. The registry descriptor cache honors its cache metadata, avoiding stale or unnecessary re-fetches, and bundled SDK installs correctly resolve the SDK's hoisted bare-* dependencies for symlinked (workspace) setups.
Model Changes
This release adds the LavaSR enhancer and denoiser assets, several Parakeet transcription models, and a Cangjie Chinese asset for Chatterbox, and refreshes the quantized multilingual Supertonic 3 model.
Added Models
PARAKEET_CTC_0_6B_F16
PARAKEET_CTC_0_6B_Q4_0
PARAKEET_EOU_120M_V1_F16
PARAKEET_SORTFORMER_4SPK_V1_F16
PARAKEET_TDT_0_6B_V3_F16
TTS_CANGJIE_ZH_CHATTERBOX
TTS_DENOISER_LAVASR_FP16
TTS_DENOISER_LAVASR_FP32
TTS_ENHANCER_LAVASR_FP16
TTS_ENHANCER_LAVASR_FP32
Updated Models
TTS_MULTILINGUAL_SUPERTONIC3_Q4_0
QVAC OpenClaw Plugin v0.1.1
Release Date: 2026-07-07
📦 NPM: https://www.npmjs.com/package/@qvac/openclaw-plugin/v/0.1.1
The first public npm release of @qvac/openclaw-plugin — an OpenClaw provider plugin that runs a local, fully managed QVAC serve so OpenClaw works against on-device models with no separate server to start.
Added
- Local QVAC provider for OpenClaw. Registers a
qvacprovider that OpenClaw drives through itslocalServicelauncher: the plugin startsqvac serveon a loopback port, exposes an OpenAI-compatible endpoint, waits for it to become healthy, and tears it down on OpenClaw's idle/exit lifecycle. - Friendly model catalog. Ships a static model catalog and OpenClaw wizard/model-picker entries using models.dev-style ids (e.g.,
qwen3.5-9b), with the friendly-id → QVAC constant mapping resolved through@qvac/ai-sdk-provider's shared catalog. Defaults toqwen3.5-9b. - Larger agent models. The catalog includes the larger agent-oriented families in addition to the Qwen3.5 line:
qwen3.6-27b,qwen3.6-35b-a3b,gpt-oss-20b, andgemma4-31b, each mapped to its@qvac/sdkmodel constant. - Layered configuration. A
configSchemaresolves options from plugin config and defaults:model,host,port,baseUrl,apiKey,qvacCommand,cwd,ctxSize,reasoningBudget,tools,readyTimeoutMs,idleStopMs, andtimeoutSeconds.
Requirements
@qvac/ai-sdk-provider@^0.3.0for the shared model catalog and managed serve.@qvac/cli@^0.8.0so the local service can runqvac serve(SDK 0.14.x runtime).openclaw@>=2026.6.0as the host (optional peer).
QVAC SDK v0.14.1
📦 NPM: https://www.npmjs.com/package/@qvac/sdk/v/0.14.1
QVAC SDK 0.14.1 is a patch release that fixes qvac bundle sdk for projects where the SDK is installed as a symlink — the common layout under pnpm and npm/yarn workspaces.
Bug Fixes
Bundling Works for Symlinked SDK Installs
Bundling the SDK worker (qvac bundle sdk) previously failed with a bare-pack error when @qvac/sdk was installed as a symlink rather than a plain copy — the layout produced by pnpm and by npm/yarn workspaces. The bundler looked for the SDK's low-level bare-* runtime dependencies relative to the symlink's location instead of where the SDK actually lives on disk, so it couldn't find them and aborted.
The bundler now resolves the SDK's worker imports against the SDK's real on-disk path, so its hoisted bare-* dependencies are found regardless of how the package was installed. Plain (copied) installs are unaffected; symlinked installs now bundle and verify successfully.
QVAC SDK v0.14.0
📦 NPM: https://www.npmjs.com/package/@qvac/sdk/v/0.14.0
QVAC SDK 0.14.0 makes the SDK quiet by default, replaces the ONNX OCR stack with a GGML backend, and expands the model registry with medical LLMs, multimodal Qwen3.5, and broader multilingual TTS. It also adds finer-grained control over completion reasoning, friendlier validation errors, and per-engine TTS language handling.
Breaking Changes
Logs Are Now Silent by Default
The SDK and its native backends (llama.cpp / ggml) no longer print to the console automatically. Applications get a clean console out of the box and explicitly opt in when they want diagnostics. SDK logs are enabled through the config file, native backend output additionally requires a debug log level, and logs can also be captured programmatically.
Before:
// SDK and native logs printed to the console by default.
await loadModel({ modelSrc: LLAMA_3_2_1B_INST_Q4_0 });
// → console fills with SDK + native outputAfter:
// Silent by default — no console output.
await loadModel({ modelSrc: LLAMA_3_2_1B_INST_Q4_0 });
// Opt in:
// qvac.config.json → { "loggerConsoleOutput": true } // SDK logs
// qvac.config.json → { "loggerConsoleOutput": true, "loggerLevel": "debug" } // + native backend output
// loggingStream({ id: SDK_LOG_ID }) // capture SDK logs programmaticallybare-process Is No Longer Bundled
The bundled bare-process shim has been removed in favor of Bare primitives. Code that relied on process as a global in Bare environments must either use the equivalent Bare primitive or install bare-process explicitly.
Before:
// process available as a global
process.exit(0);After:
import process from "bare-process";
process.exit(0);OCR Now Runs on GGML
The SDK's OCR path moves from ONNX to GGML-OCR 0.4.0. The legacy ONNX OCR model constants OCR_CRAFT_DETECTOR_GGML and OCR_LATIN_RECOGNIZER_GGML are removed; use the new GGML-backed OCR constants listed in the model changes below.
New APIs
Capture Every Server Log From One Handler
subscribeServerLogs registers a single handler that receives all server-side logs, removing the need for per-ID loggingStream() calls.
import { subscribeServerLogs } from "@qvac/sdk";
const unsubscribe = subscribeServerLogs((log) => {
console.log(`[${log.level}] [${log.namespace}] ${log.message}`);
});
// later
unsubscribe();Field-Level Validation Errors
Invalid input now produces readable, field-level errors instead of opaque failures. A RequestValidationFailedError carries a message that points at the offending field.
import { loadModel, RequestValidationFailedError, LLAMA_3_2_1B_INST_Q4_0 } from "@qvac/sdk";
try {
await loadModel({ modelSrc: LLAMA_3_2_1B_INST_Q4_0, modelConfig: { dtx_size: 4096 } });
} catch (err) {
if (err instanceof RequestValidationFailedError) {
console.error(err.message);
// Invalid request:
// ✖ Unrecognized key: "dtx_size"
// → at modelConfig
}
}Finer Control Over Reasoning
Completions can now cap or disable the reasoning channel per request or at load time via reasoning_budget, and drop a turn's reasoning block from the KV cache after generation via remove_thinking_from_context.
// Per-request: cap the reasoning channel at 128 tokens for a single run()
await session.run({
history: [{ role: "user", content: "Solve this step by step" }],
reasoning_budget: 128, // -1 = unrestricted, 0 = disabled, N = cap at N tokens
});
// Load-time default
await loadModel(src, { reasoning_budget: 256 });// Drop this turn's reasoning block from the KV cache after generation
await model.completion({
history,
generationParams: { remove_thinking_from_context: true },
});The same remove_thinking_from_context flag is accepted on the CLI's OpenAI-compatible /v1/chat/completions request body.
Multimodal Image Tiling Control
A new image_tile_mode config controls how multimodal images are tiled before inference.
await loadModel({
modelSrc: QWEN3_5_VL_MODEL,
modelType: "llamacpp-completion",
modelConfig: { image_tile_mode: "sequential" }, // "disabled" | "batched" | "sequential" (default: "sequential")
});Per-Engine TTS Language Validation and More Languages
TTS language validation is now scoped per engine, with dedicated constants and types for each backend. Chatterbox gains additional languages (he, ru, zh, hi on top of the existing multilingual set), and the tts-ggml Chatterbox config is fully exposed.
import {
TTS_CHATTERBOX_LANGUAGES,
TTS_SUPERTONIC_LANGUAGES,
type TtsChatterboxLanguage,
type TtsSupertonicLanguage,
} from "@qvac/sdk";
await loadModel({
modelSrc: TTS_T3_TURBO_EN_CHATTERBOX_Q8_0,
modelType: "tts-ggml",
modelConfig: {
ttsEngine: "chatterbox",
language: "en",
s3genModelSrc: TTS_S3GEN_EN_CHATTERBOX.src,
streamChunkTokens: 25,
streamFirstChunkTokens: 10,
cfmSteps: 1,
threads: 8,
nGpuLayers: 99,
seed: 42,
},
});Parakeet 0.8 Runtime Fields and Explicit BCI Embedder Loading
Parakeet transcription exposes new runtime fields (useGPU, backendsDir, openclCacheDir) and reports when the GPU was present but the backend routed work to the CPU. BCI transcription supports loading an explicit embedder model alongside the windowed model.
const modelId = await loadModel({
modelSrc: BCI_WINDOWED,
modelConfig: {
embedderModelSrc: BCI_EMBEDDER,
whisperConfig: { language: "en", temperature: 0.0 },
bciConfig: { day_idx: 1 },
},
});Bug Fixes
Worker startup stderr is now surfaced so worker boot failures are diagnosable. Misplaced loadModel config fields produce clearer guidance. HTTP model downloads now survive process suspension and network drops through reconnect-aware retry. Bare examples register built-in plugins (with clearer Bare docs and errors), and classification plugin bundling is fixed with added mobile e2e coverage. Qwen hybrid tool-call frames now recover correctly, GPT-OSS Harmony output is normalized, Gemma4 completion drains are hardened, and the @qvac/sdk plugin subpath stays resolvable after the publish rename.
Model Changes
This release adds healthcare/medical LLMs (1.7B and 4B variants across multiple quantizations), Qwen3.5 multimodal projectors, GGML-backed OCR constants, MeCab IPADIC Chatterbox assets, and Supertonic 3 multilingual TTS (now spanning 31 languages). The legacy ONNX OCR constants are removed in favor of the GGML OCR path.
Added Models
HEALTHCARE_1_7B_MEDICAL_BF16
HEALTHCARE_1_7B_MEDICAL_IQ3_M
HEALTHCARE_1_7B_MEDICAL_IQ3_XXS
HEALTHCARE_1_7B_MEDICAL_IQ4_NL
HEALTHCARE_1_7B_MEDICAL_IQ4_XS
HEALTHCARE_1_7B_MEDICAL_Q4_K_M
HEALTHCARE_1_7B_MEDICAL_Q5_K_M
HEALTHCARE_1_7B_MEDICAL_Q8_0
HEALTHCARE_4B_MEDICAL_BF16
HEALTHCARE_4B_MEDICAL_IQ3_M
HEALTHCARE_4B_MEDICAL_IQ3_XXS
HEALTHCARE_4B_MEDICAL_IQ4_NL
HEALTHCARE_4B_MEDICAL_IQ4_XS
HEALTHCARE_4B_MEDICAL_Q4_K_M
HEALTHCARE_4B_MEDICAL_Q5_K_M
HEALTHCARE_4B_MEDICAL_Q8_0
MMPROJ_QWEN3_5_2B_MULTIMODAL_Q8_0
MMPROJ_QWEN3_5_4B_MULTIMODAL_Q8_0
OCR_CRAFT
OCR_DOCTR
OCR_DOCTR_1
OCR_LATIN
TTS_MECAB_IPADIC_CHATTERBOX
TTS_MECAB_IPADIC_CHATTERBOX_1
TTS_MECAB_IPADIC_CHATTERBOX_2
TTS_MECAB_IPADIC_CHATTERBOX_3
TTS_MECAB_IPADIC_CHATTERBOX_4
TTS_MECAB_IPADIC_CHATTERBOX_5
TTS_MULTILINGUAL_SUPERTONIC3_FP16
TTS_MULTILINGUAL_SUPERTONIC3_FP32
TTS_MULTILINGUAL_SUPERTONIC3_Q4_0
TTS_MULTILINGUAL_SUPERTONIC3_Q8_0
Removed Models
OCR_CRAFT_DETECTOR_GGML
OCR_LATIN_RECOGNIZER_GGML
QVAC OpenCode Plugin v0.1.0
Release Date: 2026-06-16
📦 NPM: https://www.npmjs.com/package/@qvac/opencode-plugin/v/0.1.0
The first public release of @qvac/opencode-plugin — a turnkey OpenCode plugin that runs a local, fully managed QVAC serve so opencode works against on-device models with no second terminal and no manual server.
Added
- Zero-config local OpenCode. Adding
@qvac/opencode-pluginto a project'sopencode.jsonpluginarray is enough: on startup the plugin brings up a managedqvac serve, injects an OpenAI-compatibleqvacprovider pointed at it, sets it as the project default model, and tears the serve down on exit. Noproviderblock, no second terminal, noQVAC_MODEL=prefix. - Managed serve host process. The plugin spawns a host child process in a real Node/Bun runtime (OpenCode runs plugins inside its own compiled binary, which cannot spawn the detached managed-mode supervisor). The host runs
createQvac({ mode: 'managed' })from@qvac/ai-sdk-provider, which brings up a shared, idle-reaped serve on an auto-allocated port, and ensures the serve is reaped even if OpenCode is killed hard. - Non-blocking startup. The host starts a small local proxy and reports it is listening before the model finishes downloading, so
opencode runnever trips OpenCode's startup timeout; the model loads in the background and the first turn waits on it. - Shared serve across windows. Multiple OpenCode windows share one serve (the provider's
reusedefault); the detached runner owns the loaded model and reaps it a few minutes after the last session leaves, so a second window doesn't reload the model. - Friendly model ids. A models.dev-style id (e.g.
qwen3.5-9b) flows through OpenCode's model picker and the requestmodelfield, with the friendly-id → QVAC constant mapping resolved via@qvac/ai-sdk-provider's catalog. Defaults toqwen3.5-9b. - Layered configuration. Options resolve from built-in defaults, a project
qvac.json, theopencode.jsonplugin-tuple options, andQVAC_*environment variables (in increasing precedence):model,ctxSize,reasoningBudget,tools,shim,runtime,readyTimeoutMs,setDefaultModel, anddebug. - OpenAI-compatibility shim. An in-process proxy bridges
@ai-sdk/openai-compatibleand QVAC serve: it flattens arraycontentto the string form serve currently accepts, and re-routes inline<think>…</think>reasoning toreasoning_contentso OpenCode renders a collapsed "Thought" block. Disable withshim: false/QVAC_SHIM=0once serve closes those gaps; the proxy itself remains (it is what lets startup return before the model loads). - Examples. Minimal and fully-annotated
opencode.jsonexamples for adding the plugin with and without options. - Explicit static tools mode. The managed serve config pins
toolsMode: "static"so the OpenAI-compatible client surface is unambiguous across CLI versions (the invalid"auto"value leaves the serve with no loaded model).
Requirements
@qvac/ai-sdk-provider@^0.2.2for managed mode.@qvac/cli@^0.7.0so the host can runqvac serve(resolved by the provider's managed mode).
QVAC SDK v0.13.5
📦 NPM: https://www.npmjs.com/package/@qvac/sdk/v/0.13.5
A patch release that fixes Expo RPC worker cleanup on Android and other
non-iOS platforms when the SDK closes its RPC connection.
Bug Fixes
Clean up the Expo RPC worker on non-iOS close
On Expo, closing the SDK RPC connection now sends the worker a shutdown
roundtrip before dropping client-side references. On iOS the worklet can still
be terminated safely; on Android and other non-iOS platforms the worklet cannot
be terminated without risking a native crash, so the SDK releases addon logger
handles and clears worklet state instead.
After shutdown, the SDK also resets its worklet reference so the next RPC
session starts with a fresh worker and a fully populated plugin registry. This
prevents follow-up model loads from failing with "Plugin not found" when tests
or app flows unload the last model and auto-close the RPC client between runs.
The same update is mirrored into the Bare build (@qvac/bare-sdk), which ships
in lockstep with @qvac/sdk.
QVAC SDK v0.13.4
📦 NPM: https://www.npmjs.com/package/@qvac/sdk/v/0.13.4
A patch release that hardens tool-call parsing for Qwen models used in agentic
workflows.
Bug Fixes
Recover malformed Qwen tool-call frames
Qwen3.5/3.6 can intermittently emit a malformed tool-call frame that fuses its
XML and JSON tool templates, embedding the function=<name> token as a bare
string key inside an otherwise JSON object. Previously the parser rejected that
frame as invalid JSON, so no structured tool call was produced and callers saw
the raw markup as assistant text. The parser now recognizes and repairs this
specific shape, so the tool call is recovered and dispatched correctly.
QVAC AI SDK Provider v0.2.2
Release Date: 2026-06-16
📦 NPM: https://www.npmjs.com/package/@qvac/ai-sdk-provider/v/0.2.2
Fixed
- Allow managed-mode installs with either the
@qvac/cli0.6.xor0.7.xline as the optional CLI peer, so strict package managers can resolve the provider while CLI 0.7 brings in the newer SDK runtime.
QVAC SDK v0.13.3
📦 NPM: https://www.npmjs.com/package/@qvac/sdk/v/0.13.3
A maintenance patch release that updates the bundled @qvac/decoder-audio
dependency to ^0.5.0.
Dependency Changes
The bundled @qvac/decoder-audio audio decoder is updated to ^0.5.0. The same
update is mirrored into the Bare build (@qvac/bare-sdk), which ships in lockstep
with @qvac/sdk.
QVAC OCR Addon (GGML) v0.2.2
Changed
- CRAFT detector adds its convolution bias by implicit broadcast instead of
first materializing a full-size bias tensor withggml_repeat. The bias is
reshaped to[1, 1, out_channels, 1]and added directly viaggml_add,
which broadcasts on every backend (CPU, Vulkan, Metal). This removes a
per-conv allocation and copy from the detection graph — the dominant phase of
the EasyOCR pipeline — for a measured detection-time improvement (~6% on x86
CPU and a larger win on NVIDIA Vulkan GPU) with byte-for-byte identical
output across all backends. The previousggml_repeatpath remains available
as an escape hatch by settingOCR_GGML_CRAFT_BIAS_REPEAT=1.