@qvac/harness 0.8.5 → 0.8.6
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/CHANGELOG.md +55 -1
- package/README.md +49 -0
- package/dist-lib/index.d.ts +31 -2
- package/dist-lib/index.js +365 -53
- package/dist-lib/lib/audio-transcode-bare.d.ts +1 -1
- package/dist-lib/lib/audio-transcode-bare.js +22 -25
- package/dist-lib/lib/audio-transcode-node.d.ts +1 -1
- package/dist-lib/lib/audio-transcode-node.js +1 -3
- package/dist-lib/lib/capabilities/audio-resample.d.ts +1 -1
- package/dist-lib/lib/capabilities/audio-resample.js +7 -8
- package/dist-lib/lib/capabilities/completion.d.ts +5 -2
- package/dist-lib/lib/capabilities/completion.js +22 -4
- package/dist-lib/lib/capabilities/download.d.ts +3 -1
- package/dist-lib/lib/capabilities/download.js +1 -1
- package/dist-lib/lib/capabilities/preview-model-source.d.ts +1 -0
- package/dist-lib/lib/capabilities/preview-model-source.js +1 -0
- package/dist-lib/lib/capabilities/usage-breakdown.js +4 -1
- package/dist-lib/lib/capabilities/voice.d.ts +5 -1
- package/dist-lib/lib/capabilities/voice.js +94 -26
- package/dist-lib/lib/connect.d.ts +4 -1
- package/dist-lib/lib/connect.js +14 -1
- package/dist-lib/lib/contract-types.d.ts +10 -0
- package/dist-lib/lib/models/download-gate.d.ts +20 -0
- package/dist-lib/lib/models/download-gate.js +73 -0
- package/dist-lib/lib/models/memory-cap.d.ts +13 -0
- package/dist-lib/lib/models/memory-cap.js +21 -0
- package/dist-lib/lib/models/model-catalog-constants.d.ts +3 -1
- package/dist-lib/lib/models/model-catalog-constants.js +9 -1
- package/dist-lib/lib/models/model-catalog.d.ts +6 -2
- package/dist-lib/lib/models/model-catalog.js +35 -3
- package/dist-lib/lib/models/model-handle.d.ts +8 -1
- package/dist-lib/lib/models/model-handle.js +20 -2
- package/dist-lib/lib/models/model-list.d.ts +8 -1
- package/dist-lib/lib/models/model-list.js +23 -0
- package/dist-lib/lib/models/model-pool.d.ts +33 -5
- package/dist-lib/lib/models/model-pool.js +97 -29
- package/dist-lib/lib/serve.js +18 -2
- package/dist-lib/lib/tools/generate-image.d.ts +4 -2
- package/dist-lib/lib/tools/generate-image.js +5 -2
- package/dist-lib/lib/tools/generate-music.d.ts +4 -2
- package/dist-lib/lib/tools/generate-music.js +5 -2
- package/dist-lib/lib/tools/translate.d.ts +3 -1
- package/dist-lib/lib/tools/translate.js +6 -1
- package/dist-lib/schema/harness.js +41 -3
- package/dist-lib/spec/bind.js +9 -0
- package/dist-lib/spec/calls.js +3 -0
- package/dist-lib/spec/hrpc/hrpc.json +39 -0
- package/dist-lib/spec/hrpc/index.js +39 -3
- package/dist-lib/spec/hrpc/messages.js +93 -10
- package/dist-lib/spec/hyperschema/index.js +93 -10
- package/dist-lib/spec/hyperschema/schema.json +57 -1
- package/dist-lib/spec/hyperschema/types.d.ts +19 -2
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,59 @@ While the major version is `0`, a breaking change bumps the minor version.
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
## [0.8.6] - 2026-10-08
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- `setModelMemoryCap(percent)` lets loaded models fill that share of the
|
|
16
|
+
device's memory budget, so chat models a request loaded stay loaded beside
|
|
17
|
+
each other while they fit, and a chat switching between them loads neither
|
|
18
|
+
again. A load that would not fit unloads idle models one at a time: image and
|
|
19
|
+
music models first, then embedding, speech and transcription models, then
|
|
20
|
+
chat models a request loaded, then those loaded by hand, least recently used
|
|
21
|
+
first. Each load is sized by `assessModelFit`, and `list()` rows of loaded
|
|
22
|
+
models carry the estimate as `memoryBytes`; `memoryUsage()` answers their
|
|
23
|
+
total. A manual `loadModel` of any kind never unloads another model. `0`, a mobile device, and a host
|
|
24
|
+
that never sets a cap keep one chat model a request loaded, as before
|
|
25
|
+
(QVAC-25735). (#358)
|
|
26
|
+
- `setDownloadsAllowed({ allowed })`, in process and over hrpc, lets a host hold
|
|
27
|
+
model downloads. While downloads are not allowed, a load whose model is not on
|
|
28
|
+
the device emits a `model` event with `status: 'held'` and the model's
|
|
29
|
+
download name and `addon`, then waits. It goes ahead once a `download()` puts
|
|
30
|
+
the model on the device or downloads are allowed again; aborting the caller's
|
|
31
|
+
signal ends it with `AbortedError`, and a wait that ends without loading
|
|
32
|
+
reports `error` with `message: 'aborted'`. This covers the image, music and translation
|
|
33
|
+
runtimes and every pooled load (chat, embedding, speech, transcription).
|
|
34
|
+
`download()` is never held, and downloads are allowed by default. Over hrpc,
|
|
35
|
+
every model event frame now carries an `addon` field, which is `null` unless
|
|
36
|
+
the event is `held` or the `error` that ends a held wait. (#340)
|
|
37
|
+
- Ternary Bonsai 2 27B joins the curated catalog in two builds,
|
|
38
|
+
`Ternary-Bonsai-2-27B-PQ2_0` (7.2 GB) and `Ternary-Bonsai-2-27B-PTQ1_0`
|
|
39
|
+
(5.9 GB), each with its vision projection. Both sit in the `high` tier, by
|
|
40
|
+
their memory footprint rather than their parameter count. As a Qwen3.8-27B
|
|
41
|
+
fine-tune whose name the SDK's dialect router does not recognise, it parses
|
|
42
|
+
tool calls as `qwen35`; a catalog entry can now name its tool dialect. (#303)
|
|
43
|
+
|
|
44
|
+
### Changed
|
|
45
|
+
|
|
46
|
+
- `@qvac/sdk` and `@qvac/inference` 0.21.0, with `@qvac/llm-llamacpp` 0.55.0.
|
|
47
|
+
`@qvac/model-fit` leaves the native graph, and `@qvac/fabric` now ships its
|
|
48
|
+
prebuilds as per-platform packages (`@qvac/fabric-<os>-<cpu>`), so a host
|
|
49
|
+
that packages the addons exempts those names from any install age gate.
|
|
50
|
+
The fit check passes the model's source to the SDK's new `loadModel`-shaped
|
|
51
|
+
`assessModelFit` input. (#302)
|
|
52
|
+
- Transcription streams long audio to the model in 300 s segments instead of
|
|
53
|
+
decoding the whole clip first, so peak memory no longer grows with the clip's
|
|
54
|
+
length (a 3.8 h clip peaked at about 0.9 GB above baseline, down from 1.8
|
|
55
|
+
GB). Clips under 60 s are transcribed as before. (#291)
|
|
56
|
+
|
|
57
|
+
### Fixed
|
|
58
|
+
|
|
59
|
+
- A run that preloads a skill (`@skill`, or a skill named in prose) caches its
|
|
60
|
+
prompt under a child of the chat's key for the length of the run, instead of
|
|
61
|
+
prefilling the whole prompt on every round of a tool loop. The child key is
|
|
62
|
+
deleted when the run ends. (#305)
|
|
63
|
+
|
|
11
64
|
## [0.8.5] - 2026-10-06
|
|
12
65
|
|
|
13
66
|
### Added
|
|
@@ -1149,7 +1202,8 @@ Tagged but never published to npm; these changes first shipped in 0.2.12.
|
|
|
1149
1202
|
- GPU stats are read through `bare-gpu-info`, so every dependency installs from
|
|
1150
1203
|
the public npm registry. (#12)
|
|
1151
1204
|
|
|
1152
|
-
[Unreleased]: https://github.com/tetherto/qvac-harness/compare/v0.8.
|
|
1205
|
+
[Unreleased]: https://github.com/tetherto/qvac-harness/compare/v0.8.6...HEAD
|
|
1206
|
+
[0.8.6]: https://github.com/tetherto/qvac-harness/compare/v0.8.5...v0.8.6
|
|
1153
1207
|
[0.8.5]: https://github.com/tetherto/qvac-harness/compare/v0.8.0...v0.8.5
|
|
1154
1208
|
[0.8.0]: https://github.com/tetherto/qvac-harness/compare/v0.7.3...v0.8.0
|
|
1155
1209
|
[0.7.3]: https://github.com/tetherto/qvac-harness/compare/v0.7.2...v0.7.3
|
package/README.md
CHANGED
|
@@ -268,6 +268,55 @@ unloaded, and the next call loads what it needs again. The clock covers the
|
|
|
268
268
|
whole device: any call resets it, whichever model it uses. `0`, the default, is
|
|
269
269
|
Never.
|
|
270
270
|
|
|
271
|
+
## Keeping several models in memory
|
|
272
|
+
|
|
273
|
+
```js
|
|
274
|
+
await harness.setModelMemoryCap(85)
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
Loaded models may fill that percent of the device's `memoryBudget`, so two chat
|
|
278
|
+
models that fit stay loaded and a chat switching between them loads neither
|
|
279
|
+
again. A model is unloaded only when the next load would not fit, one at a time:
|
|
280
|
+
idle image and music models first, then embedding, speech and transcription
|
|
281
|
+
models, then chat models a request loaded, then chat models loaded by hand, the
|
|
282
|
+
least recently used first within each. A model a request holds stays, and a
|
|
283
|
+
load past the cap goes ahead once nothing else can give way, so a model larger
|
|
284
|
+
than the cap loads alone. A manual `loadModel`, of any kind, still never unloads
|
|
285
|
+
another model: beside what is loaded it must fit the cap, or it is refused with
|
|
286
|
+
`reason: 'memory'`. Lowering the cap unloads idle models past it at once. Loads
|
|
287
|
+
under way count by their estimate, so two at once never count on the same room.
|
|
288
|
+
|
|
289
|
+
Each load is sized by the SDK's `assessModelFit` for exactly the load it runs,
|
|
290
|
+
falling back to the download size, and `list()` rows of loaded models carry that
|
|
291
|
+
estimate as `memoryBytes`. `memoryUsage()` answers what every loaded model holds,
|
|
292
|
+
whichever list rows a host reads. `0`, and any cap on a mobile device, keeps one chat
|
|
293
|
+
model a request loaded, as without a cap; a host that never calls it keeps that
|
|
294
|
+
behaviour and sizes nothing.
|
|
295
|
+
|
|
296
|
+
## Holding model downloads
|
|
297
|
+
|
|
298
|
+
```js
|
|
299
|
+
await harness.setDownloadsAllowed({ allowed: false })
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
With downloads not allowed, a load whose model is not on the device does not
|
|
303
|
+
download it. This covers every load the harness makes: chat, embedding, speech,
|
|
304
|
+
transcription, image, music and translation. The load emits one `model` event
|
|
305
|
+
with `status: 'held'`, the model's download name and its `addon`, then waits.
|
|
306
|
+
Each `download()` that completes re-checks every waiting load, and a load goes
|
|
307
|
+
ahead once its model is on the device, or once
|
|
308
|
+
`setDownloadsAllowed({ allowed: true })` arrives, with no retry from the caller.
|
|
309
|
+
Aborting the caller's signal ends the wait with `AbortedError`, and a suspend or
|
|
310
|
+
close ends every wait. A wait that ends without loading reports `error` with
|
|
311
|
+
`message: 'aborted'`. A released wait reports nothing of its own: the `loading`
|
|
312
|
+
and `ready` after it name the model the way the pool does, which for embedding,
|
|
313
|
+
speech and transcription is not the row name. So a host clears `held` when its
|
|
314
|
+
`download()` of the row completes, when it allows downloads again, or on that
|
|
315
|
+
`error`. A model already on the device loads with no wait. The
|
|
316
|
+
check is the one `list({ cachedOnly: true })` makes, so a model counts as on the
|
|
317
|
+
device only when its companions and projection are too. `download()` itself is
|
|
318
|
+
never held. Downloads are allowed by default.
|
|
319
|
+
|
|
271
320
|
## Office extraction
|
|
272
321
|
|
|
273
322
|
Hosts can supply the bundled Python extractor to their document pipeline:
|
package/dist-lib/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { type EmbedContext } from './lib/capabilities/embed.ts';
|
|
|
10
10
|
import { type KvCacheDeletionResult } from './lib/capabilities/kv-cache.ts';
|
|
11
11
|
import type { LlmGenerationParams } from './lib/models/llm-presets.ts';
|
|
12
12
|
import { type SpeakContext, type SpeakResult, type SpeakStreamContext, type TranscribeContext } from './lib/capabilities/voice.ts';
|
|
13
|
-
import type { CapabilityInfo, CredentialEntry, HarnessDiagnostics, InfraModel, LoadModelResult, SkillsOptions, SkillWriteResult, UnloadModelContext, UnloadModelResult } from './lib/contract-types.ts';
|
|
13
|
+
import type { CapabilityInfo, CredentialEntry, HarnessDiagnostics, InfraModel, LoadModelResult, MemoryUsage, SkillsOptions, SkillWriteResult, UnloadModelContext, UnloadModelResult } from './lib/contract-types.ts';
|
|
14
14
|
import { type CustomModelEntry } from './lib/models/model-catalog.ts';
|
|
15
15
|
import { type ListModelsOptions, type ModelInfo } from './lib/models/model-list.ts';
|
|
16
16
|
import { type DeleteModelSummary } from './lib/models/model-delete.ts';
|
|
@@ -54,7 +54,7 @@ export { isAvailableState, SKILL_STATE, type SkillState } from './lib/tools/skil
|
|
|
54
54
|
export { connectHarness, HARNESS_DIED, RemoteHarness } from './lib/connect.ts';
|
|
55
55
|
export type { KvCacheDeletionResult } from './lib/capabilities/kv-cache.ts';
|
|
56
56
|
export type { AgentKnobs, ApprovalCall, ChatMessage, CredentialEntry, DownloadContext, HarnessContract, HarnessDiagnostics, HarnessEvent, HarnessInfo, HarnessStatus, InfraModel, ModelState, SkillsOptions, SkillWriteResult } from './lib/contract-types.ts';
|
|
57
|
-
import type { HarnessInfo } from './lib/contract-types.ts';
|
|
57
|
+
import type { DownloadsAllowedOptions, HarnessInfo } from './lib/contract-types.ts';
|
|
58
58
|
export { serveHarness } from './lib/serve.ts';
|
|
59
59
|
export { hlog, setHarnessLog, setHarnessLogSink } from './lib/log.ts';
|
|
60
60
|
export { harnessHooks } from './lib/hooks/registry.ts';
|
|
@@ -142,6 +142,8 @@ export declare class Harness extends ReadyResource {
|
|
|
142
142
|
private readonly _pinned;
|
|
143
143
|
private readonly _replying;
|
|
144
144
|
private readonly _modelStatus;
|
|
145
|
+
private readonly _downloads;
|
|
146
|
+
private readonly _hold;
|
|
145
147
|
private _models;
|
|
146
148
|
private _embedModels;
|
|
147
149
|
private readonly _retiredEmbedModels;
|
|
@@ -184,6 +186,11 @@ export declare class Harness extends ReadyResource {
|
|
|
184
186
|
private _capabilityInflight;
|
|
185
187
|
private readonly _modelFaults;
|
|
186
188
|
private readonly _idle;
|
|
189
|
+
private _sizeLoads;
|
|
190
|
+
private _capBytes;
|
|
191
|
+
private readonly _reserved;
|
|
192
|
+
private readonly _admission;
|
|
193
|
+
private readonly _byHand;
|
|
187
194
|
constructor({ tools, sdkLoader, skillsDir, modelsDir, projectionModel, imageModel, imageClamps, musicModel, musicClamps, llmDevice, llmGpuLayers, contextSize, kvCacheK, kvCacheV, embedDevice, embedGpuLayers, embedBatchSize, transcriptionDevice, completionModelCap, credentialStore, platform, gpuStats }?: HarnessOptions);
|
|
188
195
|
_open(): Promise<void>;
|
|
189
196
|
get suspended(): boolean;
|
|
@@ -213,6 +220,10 @@ export declare class Harness extends ReadyResource {
|
|
|
213
220
|
private _projectionFor;
|
|
214
221
|
setCustomModels(entries: ReadonlyArray<CustomModelEntry>): void;
|
|
215
222
|
setModelIdleTimeout(ms: number): void;
|
|
223
|
+
setModelMemoryCap(percent: number): Promise<void>;
|
|
224
|
+
memoryUsage(): Promise<MemoryUsage>;
|
|
225
|
+
setDownloadsAllowed({ allowed }: DownloadsAllowedOptions): void;
|
|
226
|
+
private _isModelCached;
|
|
216
227
|
previewModelSource(context: PreviewModelSourceContext): Promise<ModelSourcePreview>;
|
|
217
228
|
private _assessFit;
|
|
218
229
|
describe(): Promise<HarnessInfo>;
|
|
@@ -234,6 +245,7 @@ export declare class Harness extends ReadyResource {
|
|
|
234
245
|
private _notifyModel;
|
|
235
246
|
private _collectRetiredEmbedPool;
|
|
236
247
|
private _releaseEmbedResource;
|
|
248
|
+
private _collectRetiredEmbedPoolAfter;
|
|
237
249
|
private _releaseEmbedResourceAfter;
|
|
238
250
|
private _destroyEmbedPools;
|
|
239
251
|
private _enqueueEmbedControl;
|
|
@@ -275,6 +287,23 @@ export declare class Harness extends ReadyResource {
|
|
|
275
287
|
private _loadAndRelease;
|
|
276
288
|
private _unloadIdleGenerators;
|
|
277
289
|
private _fits;
|
|
290
|
+
private _curatedFit;
|
|
291
|
+
private _admitByHand;
|
|
292
|
+
private _replacedBy;
|
|
293
|
+
private _sizeByHand;
|
|
294
|
+
private _loadByHand;
|
|
295
|
+
private _admit;
|
|
296
|
+
private _makeRoomForGenerator;
|
|
297
|
+
private _yieldGenerators;
|
|
298
|
+
private _beforeLoad;
|
|
299
|
+
private _reserve;
|
|
300
|
+
private _sizeLoad;
|
|
301
|
+
private _makeRoom;
|
|
302
|
+
private _capVictims;
|
|
303
|
+
private _victimRank;
|
|
304
|
+
private _usedBytes;
|
|
305
|
+
private _settledBytes;
|
|
306
|
+
private _memoryByModel;
|
|
278
307
|
private _yieldPins;
|
|
279
308
|
private _residency;
|
|
280
309
|
private _completionLoadOptions;
|