In the very first lesson we called loadModel({ modelSrc: ... }) and waited. From the user's point of view the script sat there with no output while a multi-hundred-megabyte file downloaded. onProgress exists to make that wait readable.
onProgress is a callback we pass alongside modelSrc. The SDK calls it repeatedly while the model downloads. Each call hands us { percentage, downloaded, total }. We print every call, throttle to every few percent, or draw a progress bar.
Let's take a closer look at the pattern from the QVAC quickstart example. The callback goes inside the same loadModel() options object that already carries modelSrc.
onProgress runs many times during a download. The full callback wired into loadModel() would look like the following:
const modelId = await loadModel({
modelSrc: 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");
},
});
console.log("modelId:", modelId);A few details worth pointing at:
process.stderr.write is the right call here. Stdout is reserved for the model's actual response in the next lesson; progress is logging, and stderr is the standard place for it.process.stderr.isTTY flag picks the rendering mode. When the terminal is a TTY, the script writes \r so each tick overwrites the same line. When output is piped to a file, it writes \n so each tick ends up on its own row in the log.process.stderr.write("\n") after p.percentage >= 100 makes sure the next log starts on a fresh row.Question 1 of 3
Which output stream does the progress callback write its lines to?
Question 2 of 3
Given the expected output above, what does the second onProgress call receive?
Question 3 of 3
What determines whether progress output uses \r or \n after each tick?
Run your code, check your answer, or ask a question. It all shows up here.