Download lifecycle
Pause and resume model downloads.
Overview
Downloads in QVAC are resumable by default. When you download an asset via downloadAsset() or loadModel()), the SDK writes partial files to disk so the next run can continue from where it left off. The progress callback provides a downloadKey that identifies the underlying transfer (useful for dedup and cache identification), but cancellation is targeted by requestId.
Both downloadAsset() and loadModel() return a decorated promise (Promise<string> & { requestId: string }) that exposes a synchronous requestId field, so you can wire a stop button to a specific in-flight call without waiting for the first progress event. See Cancel a specific call by requestId below.
Functions
downloadAsset()orloadModel()— withonProgressfor progress tracking; both return a decorated promise that exposesop.requestIdsynchronously.cancel()— either:cancel({ requestId: op.requestId })— pause this specific call (preserves the partial file for automatic resume on the next run).cancel({ requestId: op.requestId, clearCache: true })— discard the partial file along with the cancel.cancel({ modelId })— broad sweep that cancels every in-flight request on the given model, including non-download ops. See Cancellation — broad cancel bymodelId.
For how to use each function, see SDK — API reference.
Prepare catalog models for offline use
Use downloadAsset() to provision a catalog model without loading it into memory. A later loadModel() call with the same catalog constant checks the configured cache first, validates the cached files against bundled size and checksum metadata, and can load them without contacting the registry.
import { downloadAsset, loadModel, QWEN3_4B_INST_Q4_K_M } from "@qvac/sdk";
// Run this while the registry is reachable.
await downloadAsset({ assetSrc: QWEN3_4B_INST_Q4_K_M });
// This can run offline once the download has completed.
const modelId = await loadModel({ modelSrc: QWEN3_4B_INST_Q4_K_M });The SDK instance that performs each call must use the same cacheDirectory. The initial download still requires registry access; this workflow prepares an application for later offline startup. To load a catalog model from an alternate source when the registry itself is unreachable, see Fall back to an alternate source.
If an application manages its own model files, pass a local path and an explicit model type instead:
const modelId = await loadModel({
modelSrc: "/opt/models/model.gguf",
modelType: "llamacpp-completion",
});Local-path loading does not associate the file with a catalog constant or validate it against catalog checksum metadata. Applications using this path are responsible for provisioning and integrity checks.
Fall back to an alternate source
On some networks the registry is not reliably reachable, and a loadModel() call using a catalog constant can fail before the model arrives. Pass fallbackSrc — an HTTP URL or a local file path — to load the same model from an alternate source when the registry download does not succeed:
import { loadModel, QWEN3_4B_INST_Q4_K_M } from "@qvac/sdk";
const modelId = await loadModel({
modelSrc: QWEN3_4B_INST_Q4_K_M,
fallbackSrc: "https://mirror.example.com/qwen3-4b-instruct-q4_k_m.gguf",
});The model loaded from fallbackSrc is validated against the catalog model's checksum before use, so an alternate source is trusted to the same degree as the registry copy. Download progress for the fallback is reported through the same onProgress callback.
fallbackSrc is supported only when modelSrc is a built-in catalog constant — the constant supplies the checksum to validate against. A local-path or URL modelSrc has no catalog checksum, so fallbackSrc is rejected for those. When a catalog model cannot be downloaded and no fallbackSrc was given, the error suggests supplying one.
Source trust and transport
Model sources fall into three trust tiers:
- Catalog /
registry://(andfallbackSrc) — verified against the checksum bundled with the catalog constant. AfallbackSrcis validated against that same checksum, so it is trusted to the same degree as the registry copy. - Hugging Face HTTP URLs (
huggingface.co/hf.co) — Hub-attested. The SDK reads the file's SHA-256 from the Hub (itsX-Linked-Etag) and verifies the downloaded bytes against it. This covers single-file, sharded, and archive (.tar/.tar.gz) downloads. If a Hugging Face URL exposes no SHA-256 (for example a small non-LFS file), the download proceeds unverified with a warning — unlessrequireHttpChecksumis enabled (see below). - Other HTTP(S) URLs (bring-your-own) — downloaded as-is and unverified. There is no trusted checksum to check them against. Plaintext
http://on any host is accepted and anhttps://URL that redirects tohttp://is followed — pointing at your own model server (on any domain) works unchanged. Every download whose integrity cannot be verified (bring-your-own HTTP, or a Hugging Face file with no published SHA-256) logs a warning, so an unverified load is never silent.
Because a Hugging Face download is Hub-attested, its transport is also hardened so the attestation can't be sidestepped: a Hugging Face URL served over plaintext http://, or whose redirect chain downgrades to http://, is rejected with an INSECURE_MODEL_SOURCE error (loopback excepted). This only affects huggingface.co / hf.co sources — which are HTTPS in practice — and does not apply to bring-your-own HTTP. To extend the same rule to every HTTP source, set requireSecureTransport: true in the configuration; bring-your-own HTTP must then use HTTPS too (loopback still excepted).
Require a verified checksum
Set requireHttpChecksum: true in the configuration for a stricter Hugging Face posture: a Hugging Face URL that exposes no usable SHA-256 (for example a small non-LFS file) is then rejected with a CHECKSUM_UNAVAILABLE error instead of downloading unverified. Bring-your-own HTTP is unaffected — it still downloads unverified, with a warning.
The flag defaults to false. A checksum mismatch on a Hugging Face download always fails with a CHECKSUM_VALIDATION_FAILED error, regardless of this flag.
Both requireHttpChecksum and requireSecureTransport can also be set per call on loadModel() and downloadAsset(), overriding the config for that one download:
await loadModel({
modelSrc: "https://huggingface.co/org/repo/resolve/main/model.gguf",
modelType: "llamacpp-completion",
requireSecureTransport: true,
requireHttpChecksum: true
});These flags govern downloads. A model already in the cache is served after a freshness check without re-verification, so tightening requireHttpChecksum does not retroactively verify a cache entry that was fetched before the flag was set (or before this feature shipped). Clear the cache when you tighten the setting if you need the on-disk copy re-verified.
Cancel a specific call by requestId
Both downloadAsset() and loadModel() return Promise<string> & { requestId: string }. The await result is unchanged (the asset path or model id, respectively), but op.requestId is available synchronously before await resolves — so a stop button can be wired immediately, before the first progress event arrives:
const op = downloadAsset({ assetSrc: "https://example.com/big.gguf" });
op.requestId; // synchronously available, before await
// Pause: preserves the partial file for automatic resume on the next call.
stopButton.onclick = () => cancel({ requestId: op.requestId });
// Or: discard the partial file along with the cancel.
clearButton.onclick = () => cancel({ requestId: op.requestId, clearCache: true });
await op; // rejects with InferenceCancelledError if cancelledWhen two callers request the same artifact, the SDK deduplicates them onto a single underlying transfer. cancel({ requestId }) rejects only the cancelling subscriber's promise; the underlying transfer keeps running to serve any other subscribers. The transfer is aborted only when the last subscriber leaves.
For the broader cancellation contract (errors, decorated-promise pattern across other SDK operations, broad cancel by modelId), see Cancellation.
Flow
- Pause: call
cancel()withrequestId: op.requestIdfrom the decorated promise returned bydownloadAsset()/loadModel(). - Resume: run the same
downloadAsset()/loadModel()call again — the SDK will reuse the partial file and continue downloading. - Discard partial file: call
cancel({ requestId: op.requestId, clearCache: true }).
Example
The following script shows an example of pausing and resuming a download using cancel({ requestId }) + the decorated-promise pattern:
import { cancel, close, downloadAsset, LLAMA_3_2_1B_INST_Q4_0 } from '@qvac/sdk';
console.log(`▸ Starting download with pause/resume example`);
console.log(`\n▸ Press Ctrl+C to pause the download (it will resume on restart)\n`);
let modelId;
let cancelled = false;
try {
// Download model with progress tracking and cancellation. The
// `downloadAsset(...)` call returns a *decorated* promise: the
// promise resolves to the modelId, and the same value carries a
// synchronous `requestId` field so we can cancel before it settles.
const download = downloadAsset({
assetSrc: 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');
// Example: Stops at 10% (or use Ctrl+C for manual stop)
if (p.percentage >= 10 && !cancelled) {
console.log('\n▸ Auto-cancelling at 10% for demo purposes...');
cancelled = true;
void cancel({
requestId: download.requestId
// clearCache: true, // Uncomment to delete partial file instead of resuming
});
}
}
});
modelId = await download;
console.log(`\n▸ Model downloaded successfully! Model ID: ${modelId}`);
console.log('▸ Download completed without interruption');
void close();
}
catch (error) {
if (error instanceof Error && error.message.includes('cancelled')) {
console.log('▸ Download was successfully cancelled');
void close();
}
else {
console.error('✖', error);
process.exit(1);
}
}The Python example above (model_info.py) covers related model-info and download-progress operations (get_model_info, download_asset_with_progress). For the exact pause/resume flow shown in the JavaScript/TypeScript tabs, use cancel(request_id=...) from the Python SDK — the surface is identical to cancel() in JS/TS.
Tip: all examples throughout this documentation are self-contained and runnable. For instructions on how to run them, see the JS/TS quickstart or the Python quickstart.