@qvac/llm-llamacpp 0.65.1 → 0.66.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -14
- package/addon.d.ts +11 -0
- package/addon.js +8 -0
- package/fit.d.ts +21 -20
- package/fit.js +1 -2
- package/index.d.ts +27 -1
- package/index.js +45 -0
- package/package.json +1 -1
- package/prebuilds/android-arm64/qvac__llm-llamacpp.bare +0 -0
- package/prebuilds/darwin-arm64/qvac__llm-llamacpp.bare +0 -0
- package/prebuilds/darwin-arm64/qvac__llm-llamacpp.bare.exports +15 -6
- package/prebuilds/darwin-x64/qvac__llm-llamacpp.bare +0 -0
- package/prebuilds/darwin-x64/qvac__llm-llamacpp.bare.exports +29 -8
- package/prebuilds/ios-arm64/qvac__llm-llamacpp.bare +0 -0
- package/prebuilds/ios-arm64/qvac__llm-llamacpp.bare.exports +15 -6
- package/prebuilds/ios-arm64-simulator/qvac__llm-llamacpp.bare +0 -0
- package/prebuilds/ios-arm64-simulator/qvac__llm-llamacpp.bare.exports +15 -6
- package/prebuilds/ios-x64-simulator/qvac__llm-llamacpp.bare +0 -0
- package/prebuilds/ios-x64-simulator/qvac__llm-llamacpp.bare.exports +32 -11
- package/prebuilds/linux-arm64/qvac__llm-llamacpp.bare +0 -0
- package/prebuilds/linux-x64/qvac__llm-llamacpp.bare +0 -0
- package/prebuilds/win32-x64/qvac__llm-llamacpp.bare +0 -0
- package/prebuilds/win32-x64/qvac__llm-llamacpp.bare.exports +0 -0
package/README.md
CHANGED
|
@@ -265,7 +265,7 @@ projector runs on CPU. The resolved choice is logged at verbosity ≥ 2 as
|
|
|
265
265
|
|
|
266
266
|
`spec-type: 'draft-mtp'` turns on llama-server's multi-token-prediction speculative decoding for models that ship their MTP layers (`blk.N.nextn.*`, e.g. Qwen3.5 / Qwen3.6 GGUFs that keep them; quantizations that strip them fail to load with this option unless an external head is given, see below). Every step the MTP head drafts up to `spec-draft-n-max` tokens from the model's own hidden states, the model verifies the sampled token and the draft in one decode, and the longest matching prefix plus one new token is kept. The sampler decides every kept token, so sampling settings, grammars and stop conditions behave as without speculation. The implementation follows llama-server step by step: the same draft limits, rollback by trimming or by a checkpoint for memory that cannot trim, and the same replay.
|
|
267
267
|
|
|
268
|
-
For a model without MTP layers, give an external MTP head as `spec-draft-model` (llama-server's `--spec-type draft-mtp -md <head>`): a GGUF with MTP layers for the same model, such as the MTP quantization of it, or a Gemma 4 assistant for its Gemma 4 model. The head is loaded next to the model and placed like it (`device`, `gpu-layers`), and the load's fit and `assessFit` count its weights as well as its context. A head without MTP layers fails the load, and `assessFit`
|
|
268
|
+
For a model without MTP layers, give an external MTP head as `spec-draft-model` (llama-server's `--spec-type draft-mtp -md <head>`): a GGUF with MTP layers for the same model, such as the MTP quantization of it, or a Gemma 4 assistant for its Gemma 4 model. The head is loaded next to the model and placed like it (`device`, `gpu-layers`), and the load's fit and `assessFit` count its weights as well as its context. A head without MTP layers fails the load, and `assessFit` rejects it. A head for another model, with a different hidden width or vocabulary, also fails the load, and `assessFit` rejects it the same way. A Gemma 4 assistant reads the model's own tensors, so fabric measures it next to the model, as the load creates it.
|
|
269
269
|
|
|
270
270
|
`spec-type: 'draft-dflash'` drafts with a separate DFlash model instead, given as `spec-draft-model` (an absolute path; llama-server's `-md`). The DFlash model reads the hidden states of the target layers it was trained on and denoises a whole block of draft tokens in one pass, so a step drafts up to its block size minus one tokens (`spec-draft-n-max` caps it further). It is loaded next to the model and placed like it (`device`, `gpu-layers`). The load's fit and `assessFit` count its weights and context, measured next to the model when the drafter borrows the model's embeddings and output head. A draft model fabric still cannot measure is left out of both, and fabric logs `failed to measure the memory of the extra model, fitting without it`. Everything else (verification, rollback, batching, caches, stats) is the same as for MTP.
|
|
271
271
|
|
|
@@ -384,6 +384,30 @@ const response = await model.run([
|
|
|
384
384
|
])
|
|
385
385
|
```
|
|
386
386
|
|
|
387
|
+
#### Counting tokens
|
|
388
|
+
|
|
389
|
+
`calcTokens` returns how many tokens an input takes on the loaded model, without running it:
|
|
390
|
+
|
|
391
|
+
```javascript
|
|
392
|
+
const raw = await model.calcTokens({ text: 'Hello, world!' })
|
|
393
|
+
|
|
394
|
+
const prompt = await model.calcTokens({
|
|
395
|
+
history: [{ role: 'system', content: 'You are a helpful assistant.' }],
|
|
396
|
+
tools: [{ type: 'function', name: 'get_weather', parameters: { type: 'object', properties: { city: { type: 'string' } } } }],
|
|
397
|
+
text: 'Weather in Paris?'
|
|
398
|
+
})
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
- `text` alone is counted raw, with no chat template and no BOS.
|
|
402
|
+
- `history` takes the `Message[]` that `run()` takes, and `tools` takes tool definitions. Either one is rendered by the chat template as the opening request of a fresh conversation, with `text` (even empty) appended as the last user turn. The count includes BOS, and the generation prompt when the last turn is a user or tool turn, so it equals the `promptTokens` a fresh `run()` of the same conversation reports. Tools the template drops are not counted. On an encoder-decoder model `run()` encodes the prompt separately, so its `promptTokens` differs from this count.
|
|
403
|
+
- `tools` needs `text` or `history`, as `run()` can't render tools without a message.
|
|
404
|
+
- It never queues behind `run()`, so it answers while requests are generating.
|
|
405
|
+
- Errors:
|
|
406
|
+
- A wrong-typed argument rejects with a `TypeError`.
|
|
407
|
+
- Before `load()` or after `unload()` it rejects with `Model is not loaded`.
|
|
408
|
+
- Other invalid input, media included, rejects with an error whose `code` is `InvalidArgument` and whose message starts with `calcTokens:`.
|
|
409
|
+
- A conversation the chat template cannot render at all fails as it would in `run()`.
|
|
410
|
+
|
|
387
411
|
### 7. Release Resources
|
|
388
412
|
|
|
389
413
|
Unload the model when finished:
|
|
@@ -398,7 +422,7 @@ try {
|
|
|
398
422
|
|
|
399
423
|
### API behavior by state
|
|
400
424
|
|
|
401
|
-
The following table describes the expected behavior of `run` and `
|
|
425
|
+
The following table describes the expected behavior of `run`, `cancel` and `calcTokens` depending on the current state (idle vs jobs running). The two cancel entry points have different scopes:
|
|
402
426
|
|
|
403
427
|
- `response.cancel()` — **targeted**: cancels only the job (or batch group) that `run()` call produced, leaving other concurrent jobs running.
|
|
404
428
|
- `model.cancel()` — **global**: cancels every live job (in-flight and queued) at the moment of the call, plus any finetuning in progress.
|
|
@@ -411,6 +435,7 @@ The following table describes the expected behavior of `run` and `cancel` depend
|
|
|
411
435
|
| busy, `parallel >= 2` (default `rejectWhenBusy: false`) | run | **Allowed** — the job is admitted concurrently (continuous batching) or queued until a slot frees; each call gets its own independent `QvacResponse` |
|
|
412
436
|
| busy | `response.cancel()` | **Allowed** — cancels only that response's job/group; Promise resolves when it has stopped |
|
|
413
437
|
| busy | `model.cancel()` | **Allowed** — cancels all live jobs; Promise resolves when they have stopped |
|
|
438
|
+
| idle or busy | `calcTokens` | **Allowed** — counts without running and never queues behind a job; see [Counting tokens](#counting-tokens) |
|
|
414
439
|
|
|
415
440
|
Admission is controlled by `rejectWhenBusy` (instance-level `opts.rejectWhenBusy`, overridable per call via `runOptions.rejectWhenBusy`). Its default follows `parallel`: `true` for `parallel: 1` (busy runs fail fast, preserving the historical single-job contract) and `false` for `parallel >= 2` (busy runs queue behind the pool and start as slots free). With `parallel >= 2`, separate top-level `run()` calls are batched together into the same decode loop — see [Continuous Batching](./docs/continuous-batching.md).
|
|
416
441
|
|
|
@@ -444,26 +469,33 @@ const fit = await LlmLlamacpp.assessFit({
|
|
|
444
469
|
config: { device: 'gpu', 'ctx-size': '4096' }
|
|
445
470
|
})
|
|
446
471
|
|
|
447
|
-
fit.status // 'fits' | 'does-not-fit' | '
|
|
448
|
-
fit.
|
|
449
|
-
fit.
|
|
450
|
-
fit.ctxSize
|
|
451
|
-
fit.devices // one row per device the model was assigned to, then a `host` row
|
|
452
|
-
fit.deviceBytes // model, context and compute summed across the devices, host excluded
|
|
453
|
-
fit.hostBytes // the same, for the trailing host row
|
|
472
|
+
fit.status // 'fits' | 'does-not-fit' | 'unknown'
|
|
473
|
+
fit.devices // one row per device the model is assigned to, then the host CPU
|
|
474
|
+
fit.devices[0] // { id, name, unified, usedBytes, freeBytes, totalBytes }
|
|
475
|
+
fit.stats // { ctxSize, gpuLayers }
|
|
454
476
|
```
|
|
455
477
|
|
|
456
|
-
|
|
478
|
+
Each device row gives the memory the load takes on that device, as `usedBytes`, and the device's free and total memory. `id` is the PCI bus ID when the backend reports one, and the device name otherwise. `unified` is true for memory the host owns: the CPU, an integrated GPU, a GPU that shares the host's memory, Android's OpenCL GPU, and a device that reports no memory of its own, which takes the host's figures. With `load_mode: 'mmap'`, the host row leaves out the mapped weights, which the OS can evict.
|
|
479
|
+
|
|
480
|
+
On an iOS device every unified row shares the app's own memory limit, `os_proc_available_memory()`. Each such row's free memory is capped at that limit, and a load whose unified rows together take more than the limit less the margin does not fit. A limit of 0 means the app has none left.
|
|
481
|
+
|
|
482
|
+
`stats` is the load as the fit resolved it. On `fits`, `ctxSize` and `gpuLayers` are the context and GPU layer count the fitter settled on, which can be smaller than the load asked for. On `does-not-fit` they are the ones the load asked for.
|
|
483
|
+
|
|
484
|
+
`status` is `unknown` for a load the fitter cannot project: one placed on the CPU, one with a LoRA adapter or a multimodal projector, one with `fit` turned off, or one the fitter cannot break down per device, the host CPU included. `devices` is then empty and `stats` is `{}`.
|
|
485
|
+
|
|
486
|
+
The projection reads the model's vocabulary, and llama asserts on a vocabulary it finds inconsistent. An assert aborts the process instead of rejecting, so take the model from a source you trust, or call `assessFit` behind a process boundary.
|
|
487
|
+
|
|
488
|
+
`config` is the load, exactly as `loadModel` takes it. The projection resolves it with the same code that load runs, so every setting reaches the fitter the way it would reach the engine, and a load the engine would refuse rejects here. A setting left out takes llama's default.
|
|
457
489
|
|
|
458
|
-
With `spec-type: 'draft-mtp'` the MTP draft context is fitted next to the model, as the load fits it, and its memory is in the verdict and in the
|
|
490
|
+
With `spec-type: 'draft-mtp'` the MTP draft context is fitted next to the model, as the load fits it, and its memory is in the verdict and in the device rows; on a model or head without MTP layers the load fails, so the projection rejects. A DFlash draft model or a Gemma 4 assistant is fitted the same way, measured next to the model since it reads the model's tensors, and is in the verdict and the rows too (see [Speculative decoding](#speculative-decoding-mtp-dflash)).
|
|
459
491
|
|
|
460
|
-
Pinning `gpu-layers` fixes the placement: the fitter
|
|
492
|
+
Pinning `gpu-layers` fixes the placement: the fitter keeps layers on the devices the load claimed, so the answer is for that exact placement. Leave it unset for a projection that can place the model itself.
|
|
461
493
|
|
|
462
|
-
`minCtxSize` sets a floor the fitter may not reduce the context below, defaulting to llama's own `fit-ctx` of 4096. `marginBytes` is the memory to leave free on every device
|
|
494
|
+
`minCtxSize` sets a floor the fitter may not reduce the context below, defaulting to llama's own `fit-ctx` of 4096. `marginBytes` is the memory to leave free on every device. The load's own `fit-target`, 1 GiB per device by default, applies too, and the larger of the two binds. `backendsDir` is where the dynamically-loaded ggml backends live.
|
|
463
495
|
|
|
464
496
|
`assessFit` returns a Promise. Concurrent calls run one at a time within this addon.
|
|
465
497
|
|
|
466
|
-
A model the fitter cannot read
|
|
498
|
+
A model the fitter cannot read, an invalid request, or a machine with no backend device rejects with an error whose message starts with `assessFit:` and names the cause.
|
|
467
499
|
|
|
468
500
|
## Fine-tuning
|
|
469
501
|
|
package/addon.d.ts
CHANGED
|
@@ -65,6 +65,12 @@ export interface AddonConfigurationParams {
|
|
|
65
65
|
config: Record<string, unknown>;
|
|
66
66
|
}
|
|
67
67
|
export type AddonOutputCallback = (addon: unknown, event: unknown, data: unknown, error: unknown, jobId: unknown) => void;
|
|
68
|
+
/** `calcTokens` input as the native binding takes it: `history` and `tools` are JSON array text. */
|
|
69
|
+
export interface AddonCalcTokensParams {
|
|
70
|
+
text?: string;
|
|
71
|
+
history?: string;
|
|
72
|
+
tools?: string;
|
|
73
|
+
}
|
|
68
74
|
export interface LlamaBinding {
|
|
69
75
|
createInstance(owner: LlamaInterface, configurationParams: AddonConfigurationParams, outputCallback: AddonOutputCallback, reserved: null): object;
|
|
70
76
|
loadWeights(handle: unknown, data: LoadWeightsData): Promise<void> | void;
|
|
@@ -76,6 +82,7 @@ export interface LlamaBinding {
|
|
|
76
82
|
finetune?(handle: unknown, params: FinetuneOptions): Promise<number | false> | number | false;
|
|
77
83
|
saveCache(handle: unknown, cacheKey: string): Promise<void>;
|
|
78
84
|
discardCache(handle: unknown, cacheKey: string): Promise<void>;
|
|
85
|
+
calcTokens(handle: unknown, params: AddonCalcTokensParams): Promise<number>;
|
|
79
86
|
runJob(handle: unknown, data: AddonRunJobMessage[]): Promise<AddonRunJobResult>;
|
|
80
87
|
runJob(handle: unknown, data: AddonBatchRunItem[]): Promise<AddonBatchRunResult>;
|
|
81
88
|
destroyInstance(handle: unknown): void;
|
|
@@ -138,6 +145,10 @@ export declare class LlamaInterface {
|
|
|
138
145
|
* (see `LlmLlamacpp.discardCache`).
|
|
139
146
|
*/
|
|
140
147
|
discardCache(cacheKey: string): Promise<void>;
|
|
148
|
+
/**
|
|
149
|
+
* Tokens `params` takes on the loaded model (see `LlmLlamacpp.calcTokens`).
|
|
150
|
+
*/
|
|
151
|
+
calcTokens(params: AddonCalcTokensParams): Promise<number>;
|
|
141
152
|
/**
|
|
142
153
|
* Run finetuning when native binding provides support.
|
|
143
154
|
*/
|
package/addon.js
CHANGED
|
@@ -154,6 +154,14 @@ class LlamaInterface {
|
|
|
154
154
|
return Promise.reject(new Error("Model is not loaded"));
|
|
155
155
|
return Promise.resolve(this._binding.discardCache(this._handle, cacheKey));
|
|
156
156
|
}
|
|
157
|
+
/**
|
|
158
|
+
* Tokens `params` takes on the loaded model (see `LlmLlamacpp.calcTokens`).
|
|
159
|
+
*/
|
|
160
|
+
calcTokens(params) {
|
|
161
|
+
if (!this._handle)
|
|
162
|
+
return Promise.reject(new Error("Model is not loaded"));
|
|
163
|
+
return Promise.resolve(this._binding.calcTokens(this._handle, params));
|
|
164
|
+
}
|
|
157
165
|
/**
|
|
158
166
|
* Run finetuning when native binding provides support.
|
|
159
167
|
*/
|
package/fit.d.ts
CHANGED
|
@@ -5,41 +5,42 @@ export interface LlamaFitRequest {
|
|
|
5
5
|
config?: Record<string, string>;
|
|
6
6
|
/** Floor the fitter may not reduce an unpinned context below. */
|
|
7
7
|
minCtxSize?: number;
|
|
8
|
-
/** Memory to leave free on every device
|
|
8
|
+
/** Memory to leave free on every device. The larger of this and the load's own `fit-target` binds. */
|
|
9
9
|
marginBytes?: number;
|
|
10
10
|
}
|
|
11
|
-
|
|
12
|
-
export type
|
|
11
|
+
/** `unknown` is a load the fitter cannot project, such as one placed on the CPU. */
|
|
12
|
+
export type LlamaFitStatus = 'fits' | 'does-not-fit' | 'unknown';
|
|
13
13
|
export interface LlamaFitDevice {
|
|
14
|
+
/** The PCI bus ID when the backend reports one, the device name otherwise. */
|
|
15
|
+
id: string;
|
|
14
16
|
name: string;
|
|
15
|
-
|
|
17
|
+
unified: boolean;
|
|
18
|
+
/** Model, context and compute memory the load takes on this device. */
|
|
19
|
+
usedBytes: number;
|
|
16
20
|
freeBytes: number;
|
|
17
|
-
|
|
18
|
-
contextBytes: number;
|
|
19
|
-
computeBytes: number;
|
|
21
|
+
totalBytes: number;
|
|
20
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* The load as the fit resolved it: on `fits` the context and GPU layer count the
|
|
25
|
+
* fitter settled on, on `does-not-fit` the ones the load asked for. Empty when
|
|
26
|
+
* `unknown`.
|
|
27
|
+
*/
|
|
28
|
+
export type LlamaFitStats = {
|
|
29
|
+
ctxSize: number;
|
|
30
|
+
gpuLayers: number;
|
|
31
|
+
} | Record<string, never>;
|
|
21
32
|
export interface LlamaFitResult {
|
|
22
33
|
status: LlamaFitStatus;
|
|
23
|
-
|
|
24
|
-
/** The layer count the placement resolved to. */
|
|
25
|
-
gpuLayers: number;
|
|
26
|
-
ctxSize: number;
|
|
27
|
-
/** One row per device the model was assigned to, then a `host` row. */
|
|
34
|
+
/** One row per device the model is assigned to, then the host CPU. Empty when `unknown`. */
|
|
28
35
|
devices: LlamaFitDevice[];
|
|
29
|
-
|
|
30
|
-
deviceBytes: number;
|
|
31
|
-
/** The same, for the trailing host row. */
|
|
32
|
-
hostBytes: number;
|
|
33
|
-
trainCtxSize: number;
|
|
34
|
-
expertCount: number;
|
|
36
|
+
stats: LlamaFitStats;
|
|
35
37
|
}
|
|
36
38
|
/**
|
|
37
39
|
* Projects one model against the memory free right now, reading GGUF metadata
|
|
38
40
|
* and never weight data. The registry's weightless copy of a model answers the
|
|
39
41
|
* same as the model itself, so this can run before anything is downloaded.
|
|
40
42
|
*
|
|
41
|
-
* A model the fitter cannot read
|
|
42
|
-
* request rejects.
|
|
43
|
+
* A model the fitter cannot read, or an invalid request, rejects.
|
|
43
44
|
*
|
|
44
45
|
* Builds the model twice without allocating weights. Concurrent calls run one
|
|
45
46
|
* at a time.
|
package/fit.js
CHANGED
|
@@ -6,8 +6,7 @@ exports.assessFit = assessFit;
|
|
|
6
6
|
* and never weight data. The registry's weightless copy of a model answers the
|
|
7
7
|
* same as the model itself, so this can run before anything is downloaded.
|
|
8
8
|
*
|
|
9
|
-
* A model the fitter cannot read
|
|
10
|
-
* request rejects.
|
|
9
|
+
* A model the fitter cannot read, or an invalid request, rejects.
|
|
11
10
|
*
|
|
12
11
|
* Builds the model twice without allocating weights. Concurrent calls run one
|
|
13
12
|
* at a time.
|
package/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import QvacLogger = require("@qvac/logging");
|
|
2
2
|
import { QvacResponse } from "@qvac/infer-base";
|
|
3
|
-
import { assessFit as assessFitImpl, type LlamaFitDevice, type LlamaFitRequest, type LlamaFitResult, type LlamaFitStatus } from "./fit";
|
|
3
|
+
import { assessFit as assessFitImpl, type LlamaFitDevice, type LlamaFitRequest, type LlamaFitResult, type LlamaFitStats, type LlamaFitStatus } from "./fit";
|
|
4
4
|
import type * as AddonModule from "./addon";
|
|
5
5
|
type BareEventMap = Record<string | symbol, unknown[]>;
|
|
6
6
|
/** Aliases: inside the namespace, `QvacResponse` resolves to its own member. */
|
|
@@ -9,6 +9,7 @@ type InferQvacResponseOf<Output> = QvacResponse<Output>;
|
|
|
9
9
|
/** Aliases so the class expression's body can name the namespace types below. */
|
|
10
10
|
type BatchPrompt = LlmLlamacpp.BatchPrompt;
|
|
11
11
|
type BatchResponse = LlmLlamacpp.BatchResponse;
|
|
12
|
+
type CalcTokensInput = LlmLlamacpp.CalcTokensInput;
|
|
12
13
|
type FinetuneHandle = LlmLlamacpp.FinetuneHandle;
|
|
13
14
|
type FinetuneOptions = LlmLlamacpp.FinetuneOptions;
|
|
14
15
|
type LlmLlamacppArgs = LlmLlamacpp.LlmLlamacppArgs;
|
|
@@ -70,6 +71,21 @@ interface LlmLlamacpp {
|
|
|
70
71
|
* remove the conversation from disk.
|
|
71
72
|
*/
|
|
72
73
|
discardCache(cacheKey: string): Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* Tokens `input` takes on the loaded model, without running it. `text`
|
|
76
|
+
* alone is counted raw, with no chat template and no BOS. With `history` or
|
|
77
|
+
* `tools` the conversation, `text` (even empty) appended as the last user
|
|
78
|
+
* turn, is rendered by the chat template as the opening request of a fresh
|
|
79
|
+
* conversation, with BOS and the generation prompt, as `run()` renders it.
|
|
80
|
+
* Tools the template leaves out are not counted. `tools` alone has no
|
|
81
|
+
* message to render and rejects, as `run()` does. Never queues behind
|
|
82
|
+
* `run()`: it reads only load-time state. A wrong-typed argument rejects
|
|
83
|
+
* with `TypeError`, and before `load()` it rejects with `Model is not
|
|
84
|
+
* loaded`. Other invalid input, a media message included, rejects with code
|
|
85
|
+
* `InvalidArgument`; a conversation the chat template cannot render fails
|
|
86
|
+
* as it would in `run()`.
|
|
87
|
+
*/
|
|
88
|
+
calcTokens(input: CalcTokensInput): Promise<number>;
|
|
73
89
|
getState(): {
|
|
74
90
|
configLoaded: boolean;
|
|
75
91
|
};
|
|
@@ -467,6 +483,15 @@ declare namespace LlmLlamacpp {
|
|
|
467
483
|
parameters?: Record<string, any>;
|
|
468
484
|
}
|
|
469
485
|
type Message = UserTextMessage | UserMediaMessage | ChatFunctionDefinition;
|
|
486
|
+
/** What `calcTokens` counts. At least one field is required; `tools` needs `text` or `history`. */
|
|
487
|
+
interface CalcTokensInput {
|
|
488
|
+
/** Counted raw on its own; with `history` or `tools`, the last user turn. */
|
|
489
|
+
text?: string;
|
|
490
|
+
/** A conversation in `run()`'s `Message[]` shape, tool definitions allowed. */
|
|
491
|
+
history?: Message[];
|
|
492
|
+
/** Tool definitions, as `run()` takes them. A name also in `history` rejects. */
|
|
493
|
+
tools?: ChatFunctionDefinition[];
|
|
494
|
+
}
|
|
470
495
|
interface GenerationParams {
|
|
471
496
|
temp?: number;
|
|
472
497
|
top_p?: number;
|
|
@@ -763,5 +788,6 @@ declare namespace LlmLlamacpp {
|
|
|
763
788
|
type FitResult = LlamaFitResult;
|
|
764
789
|
type FitStatus = LlamaFitStatus;
|
|
765
790
|
type FitDevice = LlamaFitDevice;
|
|
791
|
+
type FitStats = LlamaFitStats;
|
|
766
792
|
}
|
|
767
793
|
export = LlmLlamacpp;
|
package/index.js
CHANGED
|
@@ -826,6 +826,51 @@ const LlmLlamacpp = class LlmLlamacpp {
|
|
|
826
826
|
}
|
|
827
827
|
await this.addon.discardCache(cacheKey);
|
|
828
828
|
}
|
|
829
|
+
/**
|
|
830
|
+
* Tokens `input` takes on the loaded model, without running it. `text`
|
|
831
|
+
* alone is counted raw, with no chat template and no BOS. With `history` or
|
|
832
|
+
* `tools` the conversation, `text` (even empty) appended as the last user
|
|
833
|
+
* turn, is rendered by the chat template as the opening request of a fresh
|
|
834
|
+
* conversation, with BOS and the generation prompt, as `run()` renders it.
|
|
835
|
+
* Tools the template leaves out are not counted. `tools` alone has no
|
|
836
|
+
* message to render and rejects, as `run()` does. Never queues behind
|
|
837
|
+
* `run()`: it reads only load-time state. A wrong-typed argument rejects
|
|
838
|
+
* with `TypeError`, and before `load()` it rejects with `Model is not
|
|
839
|
+
* loaded`. Other invalid input, a media message included, rejects with code
|
|
840
|
+
* `InvalidArgument`; a conversation the chat template cannot render fails
|
|
841
|
+
* as it would in `run()`.
|
|
842
|
+
*/
|
|
843
|
+
async calcTokens(input) {
|
|
844
|
+
if (input === null || typeof input !== "object") {
|
|
845
|
+
throw new TypeError("calcTokens(input) requires an object");
|
|
846
|
+
}
|
|
847
|
+
const text = input.text ?? undefined;
|
|
848
|
+
const history = input.history ?? undefined;
|
|
849
|
+
const tools = input.tools ?? undefined;
|
|
850
|
+
if (text !== undefined && typeof text !== "string") {
|
|
851
|
+
throw new TypeError("calcTokens: text must be a string");
|
|
852
|
+
}
|
|
853
|
+
if (history !== undefined && !Array.isArray(history)) {
|
|
854
|
+
throw new TypeError("calcTokens: history must be a Message[]");
|
|
855
|
+
}
|
|
856
|
+
if (tools !== undefined && !Array.isArray(tools)) {
|
|
857
|
+
throw new TypeError("calcTokens: tools must be an array of function definitions");
|
|
858
|
+
}
|
|
859
|
+
if (!this.addon) {
|
|
860
|
+
throw new Error("Model is not loaded");
|
|
861
|
+
}
|
|
862
|
+
const params = {};
|
|
863
|
+
if (text !== undefined)
|
|
864
|
+
params.text = text;
|
|
865
|
+
// Media bytes are dropped rather than serialized: the native side rejects
|
|
866
|
+
// any media message by its type.
|
|
867
|
+
if (history !== undefined) {
|
|
868
|
+
params.history = JSON.stringify(history.map((message) => message?.type === "media" ? { ...message, content: "" } : message));
|
|
869
|
+
}
|
|
870
|
+
if (tools !== undefined)
|
|
871
|
+
params.tools = JSON.stringify(tools);
|
|
872
|
+
return this.addon.calcTokens(params);
|
|
873
|
+
}
|
|
829
874
|
getState() {
|
|
830
875
|
return this.state;
|
|
831
876
|
}
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
],
|
|
8
8
|
"current_versions": [
|
|
9
9
|
{
|
|
10
|
-
"version": "0.
|
|
10
|
+
"version": "0.66"
|
|
11
11
|
}
|
|
12
12
|
],
|
|
13
13
|
"exported_symbols": [
|
|
@@ -208,6 +208,7 @@
|
|
|
208
208
|
"__ZN30qvac_lib_inference_addon_llama11speculative19SpeculativeSequence4bindEPKNS0_18SpeculativeRuntimeEi",
|
|
209
209
|
"_bare_register_module_v0",
|
|
210
210
|
"__ZN12CacheManager18restoreFromRamTierENSt3__18optionalIN30qvac_lib_inference_addon_llama8batching19SlotStateCacheEntryEEE",
|
|
211
|
+
"__ZNK14TextLlmContext15countChatTokensERKNSt3__16vectorI15common_chat_msgNS0_9allocatorIS2_EEEERKNS1_I16common_chat_toolNS3_IS8_EEEE",
|
|
211
212
|
"__ZThn48_N14TextLlmContext24captureHistoryCheckpointEi",
|
|
212
213
|
"__ZN10LlamaModel22processPromptBatchImplERKNSt3__16vectorINS_6PromptENS0_9allocatorIS2_EEEERKNS0_8functionIFbmjyEEERKNS8_IFvmjEEEy",
|
|
213
214
|
"__ZN14TextLlmContext26flushPendingUtf8ToCallbackERKNSt3__18functionIFvRKNS0_12basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEEEE",
|
|
@@ -280,10 +281,9 @@
|
|
|
280
281
|
"__ZN30qvac_lib_inference_addon_llama8batching24ContinuousBatchScheduler24recordPendingGroupCancelEy",
|
|
281
282
|
"__ZN14MtmdLlmContext16evalMediaSegmentEmi",
|
|
282
283
|
"__ZNK30qvac_lib_inference_addon_llama8batching19MultiRequestBatcher14firstFreeSeqIdEv",
|
|
283
|
-
"__ZN30qvac_lib_inference_addon_llama5cache21readCheckpointSectionERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEyRKNS0_6LedgerERKNS0_16CheckpointPolicyE",
|
|
284
284
|
"__ZN30qvac_lib_inference_addon_llama8batching24ContinuousBatchScheduler17cancelGroupQueuedEy",
|
|
285
285
|
"__ZThn48_N14TextLlmContext32snapshotPreRequestRollbackAnchorEv",
|
|
286
|
-
"
|
|
286
|
+
"__ZN30qvac_lib_inference_addon_llama5cache21readCheckpointSectionERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEyRKNS0_6LedgerERKNS0_16CheckpointPolicyE",
|
|
287
287
|
"__ZN30qvac_lib_inference_addon_llama5utils34isQwen3ReasoningFamilyArchitectureENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE",
|
|
288
288
|
"__ZNK14TextLlmContext10ctxCeilingEv",
|
|
289
289
|
"__ZN10LlamaModel12formatPromptERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE",
|
|
@@ -297,7 +297,7 @@
|
|
|
297
297
|
"__ZN14LlamaFinetuner18configureOptimizerERKN30qvac_lib_inference_addon_llama21LlamaFinetuningParamsEP18llama_adapter_loraRN24llama_finetuning_helpers20LoraLrSchedulerStateEPNS6_23TrainingCheckpointStateEb",
|
|
298
298
|
"__ZThn40_NK10LlamaModel15consumeJobStatsEy",
|
|
299
299
|
"__ZN17backend_selection30getUnknownFinetuneArchitectureEPK13ModelMetaData",
|
|
300
|
-
"
|
|
300
|
+
"__ZN30qvac_lib_inference_addon_llama5utils26generationPromptTailLengthEP13llama_contextRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEERKNS3_6vectorIiNS7_IiEEEE",
|
|
301
301
|
"__ZN14TextLlmContextC1ERK13common_paramsRK15LlmModelContextii",
|
|
302
302
|
"__ZNK30qvac_lib_inference_addon_llama11speculative19SpeculativeSequence5beginERKNSt3__16vectorIiNS2_9allocatorIiEEEE",
|
|
303
303
|
"__ZNK30qvac_lib_inference_addon_llama8batching19MultiRequestBatcher17nextAwaitingMediaEv",
|
|
@@ -321,9 +321,11 @@
|
|
|
321
321
|
"__ZN14LlamaFinetuner15saveLoraAdapterEP18llama_adapter_loraRKN30qvac_lib_inference_addon_llama21LlamaFinetuningParamsE",
|
|
322
322
|
"__ZNK30qvac_lib_inference_addon_llama8batching24ContinuousBatchScheduler7hasWorkEv",
|
|
323
323
|
"__ZN14TextLlmContext22rollbackCurrentRequestERKNSt3__18functionIFvRKNS0_12basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEEEE",
|
|
324
|
+
"__ZThn48_N14MtmdLlmContext32snapshotPreRequestRollbackAnchorEv",
|
|
324
325
|
"__ZN14TextLlmContext27discardPendingResidentTokenEv",
|
|
325
326
|
"__ZThn48_N14TextLlmContext9loadCacheERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEb",
|
|
326
327
|
"__ZN14TextLlmContext20onGenerationFinishedERKNSt3__18functionIFvRKNS0_12basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEEEE20GenerationStopReason",
|
|
328
|
+
"__ZN30qvac_lib_inference_addon_llama5utils9getPromptEPK21common_chat_templatesR28common_chat_templates_inputsb",
|
|
327
329
|
"__Z23validateByteBufferCountRKNSt3__16vectorI12PlannedMediaNS_9allocatorIS1_EEEEm",
|
|
328
330
|
"__ZN14MtmdLlmContextC1ER13common_paramsNSt3__110unique_ptrI18common_init_resultNS2_14default_deleteIS4_EEEEyNS3_IN30qvac_lib_inference_addon_llama11speculative18SpeculativeRuntimeENS5_ISA_EEEE",
|
|
329
331
|
"__ZN30qvac_lib_inference_addon_llama11speculative19SpeculativeFitModel6createERK13common_params",
|
|
@@ -365,6 +367,7 @@
|
|
|
365
367
|
"__ZN14MtmdLlmContext23cancelGenerationCleanupERKNSt3__18functionIFvRKNS0_12basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEEEE",
|
|
366
368
|
"__ZN26LlamaLazyInitializeBackend7acquireERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_",
|
|
367
369
|
"__ZN14TextLlmContext14requireSamplerEv",
|
|
370
|
+
"__ZNK10LlamaModel10calcTokensERKNS_17CalcTokensRequestE",
|
|
368
371
|
"__ZN19LlamaBackendsHandleC2ERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_",
|
|
369
372
|
"__ZN24llama_finetuning_helpers23checkpointStepDirectoryERKNS_23TrainingCheckpointStateEx",
|
|
370
373
|
"__ZNK30qvac_lib_inference_addon_llama8batching24ContinuousBatchScheduler24hasRunnableSaveJobLockedEv",
|
|
@@ -458,7 +461,6 @@
|
|
|
458
461
|
"__ZN30qvac_lib_inference_addon_llama8batching24ContinuousBatchScheduler31admitPendingIntoFreeSlotsLockedEv",
|
|
459
462
|
"__ZN26LlamaLazyInitializeBackend17decrementRefCountEv",
|
|
460
463
|
"__ZN14TextLlmContext13onSequenceEndERKNSt3__18functionIFvRKNS0_12basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEEEE",
|
|
461
|
-
"__ZN30qvac_lib_inference_addon_llama5utils9getPromptEPK21common_chat_templatesR28common_chat_templates_inputs",
|
|
462
464
|
"__ZThn48_NK14MtmdLlmContext14getKvCellsUsedEv",
|
|
463
465
|
"__ZN14TextLlmContext16sampleFromLogitsEijRKNSt3__18functionIFvRKNS0_12basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEEEEP10LlamaBatch",
|
|
464
466
|
"__ZN30qvac_lib_inference_addon_llama11speculative18SpeculativeRuntime9forTargetEP13llama_context",
|
|
@@ -493,7 +495,6 @@
|
|
|
493
495
|
"__ZN14MtmdLlmContext13onLogitsReadyEijRKNSt3__18functionIFvRKNS0_12basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEEEEP10LlamaBatch",
|
|
494
496
|
"__ZN30qvac_lib_inference_addon_llama11speculative18SpeculativeRuntime6createER13common_paramsP11llama_modelP13llama_context",
|
|
495
497
|
"__ZNK18AsyncWeightsLoader25hasIndividualStreamedFileERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE",
|
|
496
|
-
"__ZThn48_N14TextLlmContext8onCancelERKNSt3__18functionIFvRKNS0_12basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEEEE",
|
|
497
498
|
"__ZN14MtmdLlmContext24snapshotPreRequestCursorEv",
|
|
498
499
|
"__ZThn48_N14MtmdLlmContext9onFailureERKNSt3__18functionIFvRKNS0_12basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEEEE",
|
|
499
500
|
"__ZN14MtmdLlmContext18onDraftLogitsReadyEiijRKNSt3__18functionIFvRKNS0_12basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEEEE",
|
|
@@ -521,6 +522,7 @@
|
|
|
521
522
|
"__ZN30qvac_lib_inference_addon_llama8batching24ContinuousBatchScheduler19discardConversationERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE",
|
|
522
523
|
"__ZN18AsyncWeightsLoader17setWeightsForFileERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEONS0_10unique_ptrINS0_15basic_streambufIcS3_EENS0_14default_deleteISB_EEEE",
|
|
523
524
|
"__ZN14MtmdLlmContext4stopEv",
|
|
525
|
+
"__ZThn48_N14TextLlmContext8onCancelERKNSt3__18functionIFvRKNS0_12basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEEEE",
|
|
524
526
|
"__ZN12CacheManager20isFileMissingOrEmptyERKNSt3__14__fs10filesystem4pathE",
|
|
525
527
|
"__ZN14TextLlmContext27restorePreRequestCacheStateEv",
|
|
526
528
|
"__ZN14TextLlmContext24captureHistoryCheckpointEi",
|
|
@@ -549,6 +551,7 @@
|
|
|
549
551
|
"__ZN30qvac_lib_inference_addon_llama8batching24ContinuousBatchScheduler29serviceNextMediaSegmentLockedEPNSt3__111unique_lockINS2_5mutexEEE",
|
|
550
552
|
"__ZNK30qvac_lib_inference_addon_llama8batching24ContinuousBatchScheduler15hasValidDriverFEv",
|
|
551
553
|
"__ZN30qvac_lib_inference_addon_llama5utils13isGemma4ModelEPK11llama_model",
|
|
554
|
+
"__ZNK14MtmdLlmContext15countChatTokensERKNSt3__16vectorI15common_chat_msgNS0_9allocatorIS2_EEEERKNS1_I16common_chat_toolNS3_IS8_EEEE",
|
|
552
555
|
"__ZN14TextLlmContext16generateResponseERKNSt3__18functionIFvRKNS0_12basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEEEE",
|
|
553
556
|
"__ZN10LlamaModel24validateCheckpointBudgetERNS_15ReloadableStateE",
|
|
554
557
|
"__ZN22load_fit_normalization31validateMobileMultiDeviceConfigERKNSt3__113unordered_mapINS0_12basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES7_NS0_4hashIS7_EENS0_8equal_toIS7_EENS5_INS0_4pairIKS7_S7_EEEEEE16llama_split_mode",
|
|
@@ -602,6 +605,7 @@
|
|
|
602
605
|
"__ZN30qvac_lib_inference_addon_llama8batching24ContinuousBatchScheduler15StepUnlockGuardC1ERS1_PNSt3__111unique_lockINS4_5mutexEEE",
|
|
603
606
|
"__ZN10LlamaModel11jobStartingEy",
|
|
604
607
|
"__ZNK10LlamaModel6cancelEv",
|
|
608
|
+
"__ZN30qvac_lib_inference_addon_llama5utils23countRenderedChatTokensEPK21common_chat_templatesRKNSt3__16vectorI15common_chat_msgNS4_9allocatorIS6_EEEERKNS5_I16common_chat_toolNS7_ISC_EEEEbbRKNS4_8functionIFNS5_IiNS7_IiEEEERKNS4_12basic_stringIcNS4_11char_traitsIcEENS7_IcEEEEEEE",
|
|
605
609
|
"__ZN30qvac_lib_inference_addon_llama5utils33sequenceStateSnapshotFilesWrittenEv",
|
|
606
610
|
"__ZN30qvac_lib_inference_addon_llama8batching24ContinuousBatchScheduler10notifyDoneEj",
|
|
607
611
|
"__ZN24llama_finetuning_helpers23parseCheckpointMetadataERKNSt3__14__fs10filesystem4pathERNS_18CheckpointMetadataE",
|
|
@@ -707,16 +711,19 @@
|
|
|
707
711
|
"__ZN30qvac_lib_inference_addon_llama9assessFitEP8js_env_sP18js_callback_info_s",
|
|
708
712
|
"__ZN30qvac_lib_inference_addon_llama6cancelEP8js_env_sP18js_callback_info_s",
|
|
709
713
|
"__ZN30qvac_lib_inference_addon_llama15fitResultObjectEP8js_env_sRKNS_9FitResultE",
|
|
714
|
+
"__ZZN28qvac_lib_inference_addon_cpp2js11JsAsyncTask5startImEEP10js_value_sP8js_env_sNS1_12CallbackDataIT_E4WorkENS9_7MarshalEENUlP11uv_handle_sE_8__invokeESD_",
|
|
710
715
|
"__ZN28qvac_lib_inference_addon_cpp2js11JsAsyncTask13onEnvTeardownINSt3__19monostateEEEvP22js_deferred_teardown_sPv",
|
|
711
716
|
"__ZN28qvac_lib_inference_addon_cpp2js11JsAsyncTask13onCloseHandleIN30qvac_lib_inference_addon_llama9FitResultEEEvP11uv_handle_s",
|
|
712
717
|
"__ZN30qvac_lib_inference_addon_llama11activeSlotsEP8js_env_sP18js_callback_info_s",
|
|
713
718
|
"__ZN28qvac_lib_inference_addon_cpp6logger8JsLogger13asyncCallbackEP10uv_async_s",
|
|
714
719
|
"__ZN28qvac_lib_inference_addon_cpp11JsInterface6cancelEP8js_env_sP18js_callback_info_s",
|
|
720
|
+
"__ZN28qvac_lib_inference_addon_cpp2js11JsAsyncTask10onCompleteImEEvP10uv_async_s",
|
|
715
721
|
"__ZN28qvac_lib_inference_addon_cpp11JsInterface10activeJobsEP8js_env_sP18js_callback_info_s",
|
|
716
722
|
"__ZN28qvac_lib_inference_addon_cpp2js11JsAsyncTask10onCompleteIN30qvac_lib_inference_addon_llama9FitResultEEEvP10uv_async_s",
|
|
717
723
|
"__ZZN28qvac_lib_inference_addon_cpp2js11JsAsyncTask5startINSt3__19monostateEEEP10js_value_sP8js_env_sNS1_12CallbackDataIT_E4WorkENSB_7MarshalEENUlP11uv_handle_sE_8__invokeESF_",
|
|
718
724
|
"__ZN30qvac_lib_inference_addon_llama12discardCacheEP8js_env_sP18js_callback_info_s",
|
|
719
725
|
"__ZN30qvac_lib_inference_addon_llama8finetuneEP8js_env_sP18js_callback_info_s",
|
|
726
|
+
"__ZN28qvac_lib_inference_addon_cpp2js11JsAsyncTask13onCloseHandleImEEvP11uv_handle_s",
|
|
720
727
|
"__ZN28qvac_lib_inference_addon_cpp11JsInterface13releaseLoggerEP8js_env_sP18js_callback_info_s",
|
|
721
728
|
"__ZZN28qvac_lib_inference_addon_cpp16OutputCallBackJs16drainAndTeardownEPNS0_5StateEbbENUlP11uv_handle_sE_8__invokeES4_",
|
|
722
729
|
"__ZN28qvac_lib_inference_addon_cpp2js11JsAsyncTask13onCloseHandleINSt3__19monostateEEEvP11uv_handle_s",
|
|
@@ -724,10 +731,12 @@
|
|
|
724
731
|
"__ZZN28qvac_lib_inference_addon_cpp6logger8JsLogger22closeAsyncHandleLockedEvENUlP11uv_handle_sE_8__invokeES3_",
|
|
725
732
|
"__ZN30qvac_lib_inference_addon_llama14createInstanceEP8js_env_sP18js_callback_info_s",
|
|
726
733
|
"__ZZN28qvac_lib_inference_addon_cpp2js11JsAsyncTask5startIN30qvac_lib_inference_addon_llama9FitResultEEEP10js_value_sP8js_env_sNS1_12CallbackDataIT_E4WorkENSB_7MarshalEENUlP11uv_handle_sE_8__invokeESF_",
|
|
734
|
+
"__ZN30qvac_lib_inference_addon_llama10calcTokensEP8js_env_sP18js_callback_info_s",
|
|
727
735
|
"__ZN30qvac_lib_inference_addon_llama6runJobEP8js_env_sP18js_callback_info_s",
|
|
728
736
|
"__ZN30qvac_lib_inference_addon_llama9saveCacheEP8js_env_sP18js_callback_info_s",
|
|
729
737
|
"__ZN28qvac_lib_inference_addon_cpp11JsInterface15destroyInstanceEP8js_env_sP18js_callback_info_s",
|
|
730
738
|
"__ZN28qvac_lib_inference_addon_cpp11JsInterface8activateEP8js_env_sP18js_callback_info_s",
|
|
739
|
+
"__ZN28qvac_lib_inference_addon_cpp2js11JsAsyncTask13onEnvTeardownImEEvP22js_deferred_teardown_sPv",
|
|
731
740
|
"__ZN28qvac_lib_inference_addon_cpp6logger8JsLogger13onEnvTeardownEPv",
|
|
732
741
|
"__ZN28qvac_lib_inference_addon_cpp11JsInterface9setLoggerEP8js_env_sP18js_callback_info_s",
|
|
733
742
|
"__ZN28qvac_lib_inference_addon_cpp11JsInterface11loadWeightsEP8js_env_sP18js_callback_info_s",
|
|
Binary file
|