# Download lifecycle (/models/download-lifecycle)



## Overview

Downloads in QVAC are *resumable by default*. When you download an asset via [`downloadAsset()`](/reference/api#downloadasset) or [`loadModel()`](/reference/api#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`](#cancel-a-specific-call-by-requestid) below.

## Functions

1. [`downloadAsset()`](/reference/api#downloadasset) or [`loadModel()`](/reference/api#loadmodel) — with `onProgress` for progress tracking; both return a decorated promise that exposes `op.requestId` synchronously.
2. [`cancel()`](/reference/api#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 by `modelId`](/runtime/cancellation#broad-cancel-by-modelid-escape-hatch).

For how to use each function, see [SDK — API reference](/reference/api/).

## 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:

```ts
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 cancelled
```

When 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](/runtime/cancellation).

## Flow

* Pause: call [`cancel()`](/reference/api#cancel) with `requestId: op.requestId` from the decorated promise returned by `downloadAsset()` / `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:

<Tabs>
  <Tab value="js" label="JavaScript" default>
    <WrapCode>
      ```js file=<rootDir>/packages/sdk/dist/examples/download-with-cancel.js title="download-lifecycle.js" lineNumbers
      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);
          }
      }
      ```
    </WrapCode>
  </Tab>

  <Tab value="ts" label="TypeScript">
    <WrapCode>
      ```ts file=<rootDir>/packages/sdk/examples/download-with-cancel.ts title="download-lifecycle.ts" lineNumbers
      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: string | undefined;
      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: number) => (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);
        }
      }
      ```
    </WrapCode>
  </Tab>
</Tabs>

<Callout type="success">
  **Tip:** all examples throughout this documentation are self-contained and runnable. For instructions on how to run them, see [SDK quickstart](/quickstart).
</Callout>
