@qvac/harness 0.5.0 → 0.7.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/CHANGELOG.md +142 -1
- package/README.md +78 -27
- package/dist-lib/index.d.ts +15 -1
- package/dist-lib/index.js +175 -53
- package/dist-lib/lib/capabilities/preview-model-source.d.ts +0 -1
- package/dist-lib/lib/connect.d.ts +3 -1
- package/dist-lib/lib/connect.js +23 -2
- package/dist-lib/lib/contract-types.d.ts +14 -0
- package/dist-lib/lib/docx/index.d.ts +1 -1
- package/dist-lib/lib/docx/index.js +1 -1
- package/dist-lib/lib/hardware/capability-probe.js +9 -4
- package/dist-lib/lib/hooks/built-in/sandbox.js +0 -5
- package/dist-lib/lib/models/model-catalog-constants.d.ts +7 -0
- package/dist-lib/lib/models/model-catalog-constants.js +17 -0
- package/dist-lib/lib/models/model-catalog.d.ts +16 -6
- package/dist-lib/lib/models/model-catalog.js +21 -6
- package/dist-lib/lib/models/model-list.d.ts +2 -0
- package/dist-lib/lib/models/model-list.js +9 -4
- package/dist-lib/lib/models/model-pool.d.ts +6 -2
- package/dist-lib/lib/models/model-pool.js +67 -11
- package/dist-lib/lib/models/model-task.d.ts +3 -0
- package/dist-lib/lib/models/model-task.js +14 -0
- package/dist-lib/lib/models/music-catalog.d.ts +2 -0
- package/dist-lib/lib/models/music-catalog.js +9 -0
- package/dist-lib/lib/office/index.d.ts +1 -1
- package/dist-lib/lib/office/index.js +1 -1
- package/dist-lib/lib/office/python.js +1 -2
- package/dist-lib/lib/serve.js +12 -0
- package/dist-lib/lib/tools/exec/adapters/python/deadline-state.d.ts +10 -0
- package/dist-lib/lib/tools/exec/adapters/python/deadline-state.js +5 -0
- package/dist-lib/lib/tools/exec/adapters/python/interrupt-timer.js +10 -17
- package/dist-lib/lib/tools/exec/adapters/python/loader.js +15 -11
- package/dist-lib/lib/tools/exec/adapters/python/pyodide.js +1 -15
- package/dist-lib/lib/tools/exec/adapters/python/python-adapter.d.ts +1 -0
- package/dist-lib/lib/tools/exec/adapters/python/python-adapter.js +13 -2
- package/dist-lib/lib/tools/exec/adapters/python/wheels.d.ts +3 -3
- package/dist-lib/lib/tools/exec/adapters/python/wheels.js +3 -14
- package/dist-lib/lib/tools/exec/adapters/python/worker/active.d.ts +19 -0
- package/dist-lib/lib/tools/exec/adapters/python/worker/active.js +72 -0
- package/dist-lib/lib/tools/exec/adapters/python/worker/client.d.ts +0 -1
- package/dist-lib/lib/tools/exec/adapters/python/worker/client.js +8 -76
- package/dist-lib/lib/tools/exec/adapters/python/worker/entry.js +2 -126
- package/dist-lib/lib/tools/exec/adapters/python/worker/interrupt-deadline.d.ts +1 -0
- package/dist-lib/lib/tools/exec/adapters/python/worker/interrupt-deadline.js +21 -0
- package/dist-lib/lib/tools/exec/adapters/python/worker/serve.d.ts +2 -0
- package/dist-lib/lib/tools/exec/adapters/python/worker/serve.js +90 -0
- package/dist-lib/lib/tools/exec/adapters/python/worker/{spawn-node.d.ts → spawn.d.ts} +0 -1
- package/dist-lib/lib/tools/exec/adapters/python/worker/{spawn-node.js → spawn.js} +0 -8
- package/dist-lib/lib/tools/exec/bare-runtime.d.ts +2 -0
- package/dist-lib/lib/tools/exec/bare-runtime.js +10 -0
- package/dist-lib/lib/tools/exec.d.ts +0 -2
- package/dist-lib/lib/tools/exec.js +6 -11
- package/dist-lib/schema/harness.js +27 -1
- package/dist-lib/spec/bind.js +6 -0
- package/dist-lib/spec/calls.js +2 -0
- package/dist-lib/spec/hrpc/hrpc.json +26 -0
- package/dist-lib/spec/hrpc/index.js +27 -3
- package/dist-lib/spec/hrpc/messages.js +72 -5
- package/dist-lib/spec/hyperschema/index.js +72 -5
- package/dist-lib/spec/hyperschema/schema.json +53 -1
- package/dist-lib/spec/hyperschema/types.d.ts +18 -1
- package/package.json +40 -20
- package/dist/harness.bundle +0 -42312
- package/dist/harness.cjs +0 -18
- package/dist/harness.d.ts +0 -8
- package/dist/prebuilds-manifest.json +0 -372
- package/dist-lib/lib/tools/exec/adapters/python/worker/spawn-bare.d.ts +0 -3
- package/dist-lib/lib/tools/exec/adapters/python/worker/spawn-bare.js +0 -38
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,145 @@ While the major version is `0`, a breaking change bumps the minor version.
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
## [0.7.0] - 2026-09-29
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- `list()` rows carry `taskType`, what the model is for: `llm`, `embeddings`,
|
|
16
|
+
`speech-to-text`, `text-to-speech`, `image-generation`, `audio-generation`,
|
|
17
|
+
`translation`, `text-recognition` or `other`. It is decided from the addon in
|
|
18
|
+
one place, `lib/models/model-task.ts`, on each side of the wire rather than
|
|
19
|
+
sent over it. `ModelTaskType` is exported, and grows the four new values a
|
|
20
|
+
preview never returns. (#140)
|
|
21
|
+
|
|
22
|
+
- `modelsForAgent(agent, host)` lists every model an agent runs on a device,
|
|
23
|
+
each with its `use`: the chat model, clamped by `runnableModelName`, then the
|
|
24
|
+
image and music models its skills need. A host deciding what to download, or
|
|
25
|
+
which agents a model delete affects, asks this instead of working it out.
|
|
26
|
+
`runnableModelName(requested, host)` and `isMobilePlatform(platform)` move here
|
|
27
|
+
from `@qvac/core`: on a phone a pick above the device's profile runs as its
|
|
28
|
+
recommended model. Whether the host is a phone is the required `mobile` on
|
|
29
|
+
`HostCapability`, which `capability()` now reports, so its answer passes
|
|
30
|
+
straight in; a host built by hand has to say. Both functions are on the
|
|
31
|
+
browser-safe `@qvac/harness/model-catalog` entry too. (#141)
|
|
32
|
+
|
|
33
|
+
```js
|
|
34
|
+
const chat = modelsForAgent(agent, await harness.capability()).find((m) => m.use === 'chat')
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
- `capability()` answers `mobile`, whether the harness runs on a phone, read off
|
|
38
|
+
the platform it probes. It rides `capability-response` as an optional field;
|
|
39
|
+
a response from an older harness reads as `false`. (#141)
|
|
40
|
+
|
|
41
|
+
- `musicModelChoiceFrom(settings)` reads the music model pick out of an agent's
|
|
42
|
+
`generate_music` tool settings, so a host no longer knows what `modelChoice`
|
|
43
|
+
means there. `isMusicModelChoice` is exported beside it. (#141)
|
|
44
|
+
|
|
45
|
+
### Changed
|
|
46
|
+
|
|
47
|
+
- **Breaking:** the package no longer publishes a prebuilt sidecar:
|
|
48
|
+
`dist/harness.bundle`, `dist/harness.cjs`, `dist/prebuilds-manifest.json` and
|
|
49
|
+
the `./dist/harness.cjs` export are gone. A host stows
|
|
50
|
+
`worker/harness-sidecar.mjs` itself, as desktop and mobile already do, or
|
|
51
|
+
spawns `worker/stow-entry.mjs` straight from its install. (#127)
|
|
52
|
+
- **Breaking:** a stowed harness runs python in a worker rather than in-process.
|
|
53
|
+
A host that stows the harness stops deferring `pyodide`, keeps
|
|
54
|
+
`QVAC_PYODIDE_CACHE_DIR` writable, no longer stages a separate worker bundle,
|
|
55
|
+
and ships what stow offloads beside the bundle, which now includes pyodide's
|
|
56
|
+
wasm, stdlib and lock file and the vendored wheels. A target that embeds
|
|
57
|
+
assets instead of offloading them cannot run python, since `fs` cannot read
|
|
58
|
+
inside a bundle. (#127)
|
|
59
|
+
- A bundle of the package root carries neither pyodide nor the vendored wheels.
|
|
60
|
+
Only an entry that runs python, the exec tool or `@qvac/harness/docx` and
|
|
61
|
+
`/office`, pulls them in. (#127)
|
|
62
|
+
- `SandboxHook` no longer checks `packages`. The exec tool refuses an install
|
|
63
|
+
the vendored wheels do not hold in full in sandbox mode, whether declared in
|
|
64
|
+
`packages` or on a pip line, with the same message as before. (#127)
|
|
65
|
+
- The vendored wheels are the `#pyodide-wheels` directory asset on Bare;
|
|
66
|
+
`QVAC_PYTHON_WHEELS_DIR` still overrides it. (#127)
|
|
67
|
+
- The python worker and the in-process deadline are spawned through
|
|
68
|
+
`worker_threads`, which the package maps to `bare-worker`;
|
|
69
|
+
`#pyodide-worker-spawn` is gone. (#127)
|
|
70
|
+
- **Breaking:** `engines.bare` is `>=1.34.0`, so Bare refuses to load the
|
|
71
|
+
package on older runtimes. `bare-runtime` is pinned to 1.34.0 and
|
|
72
|
+
`bare-sidecar` to 0.5.7 (Bare 1.34.0) across the tree, `bare-supervisor`'s copy
|
|
73
|
+
included, with `bare-thread` at least 1.2.7 and `bare-module` 7.1.0 for
|
|
74
|
+
`bare-worker`'s copy. (#127)
|
|
75
|
+
- `bare-module` is no longer a dependency or an override, and
|
|
76
|
+
`bare-module-traverse` is overridden to 2.5.8: earlier versions drop the
|
|
77
|
+
`asset` condition on `bare-sidecar`'s binary, and a stowed harness then fails
|
|
78
|
+
to boot on Bare 1.33 and later. (#127)
|
|
79
|
+
- `skillModelsForAgent` rows carry `use`, `image` or `music`, so a caller can
|
|
80
|
+
tell which skill a model is for without looking the name up in the catalogs. (#141)
|
|
81
|
+
- `CapabilityInfo` has a required `mobile`, so a `HarnessContract` whose
|
|
82
|
+
`capability()` builds its own answer, a test stub included, returns it too. (#141)
|
|
83
|
+
|
|
84
|
+
### Removed
|
|
85
|
+
|
|
86
|
+
- **Breaking:** `bareRuntime` is no longer exported from `./lib/tools/exec.ts`.
|
|
87
|
+
It is at `./lib/tools/exec/bare-runtime.ts`, so the package root no longer
|
|
88
|
+
loads the exec tool to reach it. (#127)
|
|
89
|
+
- **Breaking:** `QVAC_PYODIDE_TEST_LOADER`: tests point
|
|
90
|
+
`QVAC_PYODIDE_WORKER_ENTRY` at an entry that serves their fake interpreter. (#127)
|
|
91
|
+
|
|
92
|
+
### Fixed
|
|
93
|
+
|
|
94
|
+
- Python runs start on Bare 1.34, whose threads cannot read a module off disk,
|
|
95
|
+
including in a stowed harness. The worker is spawned through `worker_threads`,
|
|
96
|
+
which the package maps to `bare-worker` on Bare, pyodide is handed its asm
|
|
97
|
+
module as `createPyodideModule`, and the files pyodide reads are named as
|
|
98
|
+
assets, so a bundler carries them beside the bundle. (#127)
|
|
99
|
+
|
|
100
|
+
## [0.6.0] - 2026-09-28
|
|
101
|
+
|
|
102
|
+
### Added
|
|
103
|
+
|
|
104
|
+
- `loadModel({ model, agent })` loads a downloaded chat, embedding, speech or
|
|
105
|
+
transcription model ahead of use, under the key a request for it would load
|
|
106
|
+
under, so the first request finds it loaded. `unloadModel({ model })` unloads
|
|
107
|
+
every copy of a model once the requests holding it finish, and says whether it
|
|
108
|
+
could. Image and music models load for each generation and are refused. A load
|
|
109
|
+
or an unload counts as a call in flight for `setModelIdleTimeout`, and one that
|
|
110
|
+
lands during an idle unload waits for it. Also on the wire as `load-model` and
|
|
111
|
+
`unload-model`. (#133)
|
|
112
|
+
|
|
113
|
+
```js
|
|
114
|
+
const { loaded } = await harness.loadModel({ model: QWEN_35_4B, agent: { ctxSize: 8192 } })
|
|
115
|
+
const { unloaded } = await harness.unloadModel({ model: QWEN_35_4B })
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
- A chat model loaded with `loadModel` is pinned: it does not count against
|
|
119
|
+
`completionModelCap`, so several stay loaded at once and a request for
|
|
120
|
+
another model leaves them in place. A manual load never unloads another model
|
|
121
|
+
to fit; it returns `{ loaded: false, reason: 'memory' }` when the SDK's
|
|
122
|
+
`assessModelFit` says it would not fit beside what is loaded. A request always
|
|
123
|
+
gets its model: pinned models no reply is using give way oldest first when it would not fit,
|
|
124
|
+
and a request or a manual load for a model under other settings replaces its idle copy. Image and
|
|
125
|
+
music generation and an idle unload still clear every idle chat model. (#134)
|
|
126
|
+
|
|
127
|
+
```js
|
|
128
|
+
const { loaded, reason } = await harness.loadModel({ model: QWEN_35_9B })
|
|
129
|
+
if (reason === 'memory') showNotice('Unload a model first')
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Changed
|
|
133
|
+
|
|
134
|
+
- A model loading or unloading in any pool emits `model` with `catalogChanged`,
|
|
135
|
+
not only a chat model, so `list()` reports a fresh `isLoaded` for embedding,
|
|
136
|
+
speech and transcription models too. (#133)
|
|
137
|
+
- Speech, transcription and embedding requests key their pool entry by the
|
|
138
|
+
model's registry src however the caller names it, so a model named once by
|
|
139
|
+
its catalog name and once by its src is one copy in memory. (#133)
|
|
140
|
+
|
|
141
|
+
### Fixed
|
|
142
|
+
|
|
143
|
+
- A chat model loads when the host passes no `llmDevice`. 0.5.0 sent `device`,
|
|
144
|
+
`gpu_layers`, `main-gpu` and `openclCacheDir` to the SDK as `undefined`,
|
|
145
|
+
which the SDK spreads over its defaults: with no device the load failed with
|
|
146
|
+
"must specify a device: 'gpu' or 'cpu'", and with a device but no
|
|
147
|
+
`llmGpuLayers` the default of 99 GPU layers was lost. Unset fields are left
|
|
148
|
+
out again. (#137)
|
|
149
|
+
|
|
11
150
|
## [0.5.0] - 2026-09-25
|
|
12
151
|
|
|
13
152
|
### Added
|
|
@@ -840,7 +979,9 @@ Tagged but never published to npm; these changes first shipped in 0.2.12.
|
|
|
840
979
|
- GPU stats are read through `bare-gpu-info`, so every dependency installs from
|
|
841
980
|
the public npm registry. (#12)
|
|
842
981
|
|
|
843
|
-
[Unreleased]: https://github.com/tetherto/qvac-harness/compare/v0.
|
|
982
|
+
[Unreleased]: https://github.com/tetherto/qvac-harness/compare/v0.7.0...HEAD
|
|
983
|
+
[0.7.0]: https://github.com/tetherto/qvac-harness/compare/v0.6.0...v0.7.0
|
|
984
|
+
[0.6.0]: https://github.com/tetherto/qvac-harness/compare/v0.5.0...v0.6.0
|
|
844
985
|
[0.5.0]: https://github.com/tetherto/qvac-harness/compare/v0.4.0...v0.5.0
|
|
845
986
|
[0.4.0]: https://github.com/tetherto/qvac-harness/compare/v0.3.3...v0.4.0
|
|
846
987
|
[0.3.3]: https://github.com/tetherto/qvac-harness/compare/v0.3.2...v0.3.3
|
package/README.md
CHANGED
|
@@ -12,41 +12,40 @@ the supervision contract.
|
|
|
12
12
|
|
|
13
13
|
## The published package
|
|
14
14
|
|
|
15
|
-
The published package ships the
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
- `dist
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
15
|
+
The published package ships the library and its runtime content, not a prebuilt
|
|
16
|
+
engine:
|
|
17
|
+
|
|
18
|
+
- `dist-lib/` — the compiled library and its declarations. The package exports
|
|
19
|
+
resolve to it; the TypeScript source stays in the repository.
|
|
20
|
+
- `worker/harness-sidecar.mjs` — the sidecar entry a host stows into its own
|
|
21
|
+
bundle, and `worker/stow-entry.mjs`, the same entry as a plain file for a
|
|
22
|
+
host that spawns it straight from its install
|
|
22
23
|
- the hash-pinned Python `wheels/` the tool runtime consumes (skills come from
|
|
23
24
|
[`@qvac/skills`](https://github.com/tetherto/qvac-skills), a content-addressed
|
|
24
25
|
bundle this package materializes at runtime)
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
`
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
model catalogs, skill helpers and DOCX extractor — ships as compiled JavaScript
|
|
32
|
-
and declarations in `dist-lib/`. The package exports resolve to that surface;
|
|
33
|
-
the TypeScript source stays in the repository.
|
|
27
|
+
A host that stows the harness defers the `@qvac` inference addons
|
|
28
|
+
(`scripts/addon-externals.cjs` lists them), so they resolve from real files
|
|
29
|
+
beside the bundle, and ships everything stow offloads there: prebuilds, and
|
|
30
|
+
pyodide's data and the wheels, which the harness names as assets. A target that
|
|
31
|
+
embeds assets instead cannot run python.
|
|
34
32
|
|
|
35
33
|
## Spawning
|
|
36
34
|
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
`spawnHarness` spawns an entry as a bare-sidecar process and hands back a
|
|
36
|
+
client over hrpc:
|
|
39
37
|
|
|
40
38
|
```js
|
|
41
|
-
|
|
39
|
+
import { spawnHarness } from '@qvac/harness'
|
|
42
40
|
|
|
43
|
-
const {
|
|
41
|
+
const harness = spawnHarness({ entry, sdkStorage })
|
|
44
42
|
```
|
|
45
43
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
`entry` is the host's own stowed bundle, or `@qvac/harness/worker/stow-entry.mjs`
|
|
45
|
+
resolved from its install. The argv slots the entry reads (skills dir, sdk
|
|
46
|
+
storage, model config, wheels dir, ...) are the ones
|
|
47
|
+
`worker/harness-sidecar.mjs` documents; `harnessChild` does the same under
|
|
48
|
+
bare-supervisor.
|
|
50
49
|
|
|
51
50
|
## Custom models
|
|
52
51
|
|
|
@@ -168,7 +167,8 @@ const custom = models.filter((model) => model.registrySource === 'custom')
|
|
|
168
167
|
// isLoaded: false,
|
|
169
168
|
// supportsImages: false,
|
|
170
169
|
// expectedSize: 1868506272,
|
|
171
|
-
// label: 'Nanbeige 4.2 3B'
|
|
170
|
+
// label: 'Nanbeige 4.2 3B',
|
|
171
|
+
// taskType: 'llm'
|
|
172
172
|
// }
|
|
173
173
|
```
|
|
174
174
|
|
|
@@ -181,6 +181,11 @@ sidecar knows from `sdkStorage.models`; an in-process `Harness` needs
|
|
|
181
181
|
`new Harness({ modelsDir })` for it. A sharded download is looked for in the
|
|
182
182
|
folder the SDK keeps its shards in, and is cached once every shard is there.
|
|
183
183
|
|
|
184
|
+
Every row, catalog or custom, carries `taskType`: what the model is for, in the
|
|
185
|
+
vocabulary a preview uses, so a Models screen groups by task rather than by
|
|
186
|
+
addon. `whisper` and `parakeet` are both `speech-to-text`, and an addon with no
|
|
187
|
+
task of its own is `other`.
|
|
188
|
+
|
|
184
189
|
### Delete a download
|
|
185
190
|
|
|
186
191
|
```js
|
|
@@ -193,6 +198,52 @@ user's files. The model stays registered and
|
|
|
193
198
|
lists as not cached, ready to download again. Like a catalog delete, it does not
|
|
194
199
|
unload a model that is running.
|
|
195
200
|
|
|
201
|
+
### Load and unload a model
|
|
202
|
+
|
|
203
|
+
```js
|
|
204
|
+
import { QWEN_35_4B } from '@qvac/harness'
|
|
205
|
+
|
|
206
|
+
const { loaded } = await harness.loadModel({ model: QWEN_35_4B, agent: { ctxSize: 8192 } })
|
|
207
|
+
const row = (await harness.list({ cachedOnly: true })).find((model) => model.name === QWEN_35_4B)
|
|
208
|
+
// row.isLoaded === true, and the next completion with the same agent reuses it
|
|
209
|
+
|
|
210
|
+
const { unloaded } = await harness.unloadModel({ model: QWEN_35_4B })
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
`loadModel` loads a downloaded model ahead of use, under the key a request for it
|
|
214
|
+
would load under, so the first request does not load it again. Pass the agent a
|
|
215
|
+
chat model will run for, since its context size and KV cache types are part of
|
|
216
|
+
that key. Chat, embedding, speech and transcription models stay loaded; image and
|
|
217
|
+
music models load for each generation and are refused.
|
|
218
|
+
|
|
219
|
+
A chat model loaded this way is pinned. It does not count against
|
|
220
|
+
`completionModelCap`, so several can be loaded at once, and a request loading
|
|
221
|
+
another model leaves it in place. A request or a manual load for the same model
|
|
222
|
+
under other settings replaces its idle copy rather than loading a second one. A
|
|
223
|
+
manual load never unloads another model to fit: `{ loaded: false, reason: 'memory' }` means the
|
|
224
|
+
SDK's `assessModelFit` estimate says it would not fit beside what is loaded, so
|
|
225
|
+
unload one first. A request always gets its model, though: when that would not
|
|
226
|
+
fit, pinned models no reply is using give way, oldest first. Image or music generation and an idle
|
|
227
|
+
unload still clear every idle chat model, pinned or not.
|
|
228
|
+
|
|
229
|
+
```js
|
|
230
|
+
const big = await harness.loadModel({ model: QWEN_36_27B, agent: { ctxSize: 262144 } })
|
|
231
|
+
if (big.reason === 'memory') showNotice('Unload a model first')
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
`unloadModel` waits for any request holding the model to finish, then unloads
|
|
235
|
+
every copy of it. `unloaded` is false when a request still held it after the
|
|
236
|
+
wait, so a caller that wants the model gone at once stops those requests first.
|
|
237
|
+
Both change `isLoaded` in the next `list()`, and emit a `model` event with
|
|
238
|
+
`catalogChanged` set. A load or an unload counts as a call in flight for
|
|
239
|
+
[`setModelIdleTimeout`](#freeing-memory-when-idle), and one that lands during an
|
|
240
|
+
idle unload waits for it, so a load never loads a second copy and an unload
|
|
241
|
+
answers once the memory is free.
|
|
242
|
+
|
|
243
|
+
`bun run model-residency` (`bare examples/model-residency/run.ts`, with
|
|
244
|
+
`QVAC_MODEL_CACHE_PATH` pointing at the models) runs these calls against the
|
|
245
|
+
models already on disk and prints what each step changed. It never downloads.
|
|
246
|
+
|
|
196
247
|
## Freeing memory when idle
|
|
197
248
|
|
|
198
249
|
```js
|
|
@@ -227,8 +278,8 @@ are not extracted. Legacy XLS/PPT formats are unsupported. File extensions selec
|
|
|
227
278
|
format, with `mimeType` as a fallback when the name has no recognized Office extension.
|
|
228
279
|
|
|
229
280
|
The extractor accepts up to 20 MiB and requires the shipped Python wheels. With the
|
|
230
|
-
cache configured, extraction uses those wheels offline.
|
|
231
|
-
|
|
281
|
+
cache configured, extraction uses those wheels offline. A host that stows the harness ships them
|
|
282
|
+
with what stow offloads beside the bundle; `QVAC_PYTHON_WHEELS_DIR` names another directory.
|
|
232
283
|
Source checkouts prepare wheels with `bun run vendor:wheels`.
|
|
233
284
|
|
|
234
285
|
The existing `extractDocxText` and `closeDocxWorker` exports from `@qvac/harness/docx`
|
|
@@ -241,7 +292,7 @@ bun install
|
|
|
241
292
|
bun run lint # prettier + lunte + tsc
|
|
242
293
|
bun run test # brittle, node and bare lanes
|
|
243
294
|
bun run build:schema # regenerates spec/ (wire-compat rewind once v* tags exist)
|
|
244
|
-
bun run build:bundle # stows dist
|
|
295
|
+
bun run build:bundle # stows the sidecar entry into dist/, to prove it still stows
|
|
245
296
|
```
|
|
246
297
|
|
|
247
298
|
The schema baseline rewinds `spec/` against this repo's `v*` release tags and
|
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, SkillsOptions, SkillWriteResult } from './lib/contract-types.ts';
|
|
13
|
+
import type { CapabilityInfo, CredentialEntry, HarnessDiagnostics, InfraModel, LoadModelResult, 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';
|
|
@@ -38,6 +38,7 @@ export type { EmbedDevice } from './lib/models/embed-config.ts';
|
|
|
38
38
|
export type { MemoryBudget } from './lib/hardware/memory-budget.ts';
|
|
39
39
|
export * from './lib/models/model-catalog.ts';
|
|
40
40
|
export * from './lib/models/model-list.ts';
|
|
41
|
+
export type { ModelTaskType } from './lib/models/model-task.ts';
|
|
41
42
|
export type { DeleteModelResult, DeleteModelSummary } from './lib/models/model-delete.ts';
|
|
42
43
|
export { harnessChild, spawnHarness, type HarnessChildOptions, type SpawnHarnessOptions } from './lib/spawn.ts';
|
|
43
44
|
export { settingsDimension, settingsSteps } from './lib/tools/generate-image.ts';
|
|
@@ -138,6 +139,8 @@ export declare class Harness extends ReadyResource {
|
|
|
138
139
|
private _tools;
|
|
139
140
|
private _sdk;
|
|
140
141
|
private readonly _loads;
|
|
142
|
+
private readonly _pinned;
|
|
143
|
+
private readonly _replying;
|
|
141
144
|
private readonly _modelStatus;
|
|
142
145
|
private _models;
|
|
143
146
|
private _embedModels;
|
|
@@ -211,6 +214,7 @@ export declare class Harness extends ReadyResource {
|
|
|
211
214
|
setCustomModels(entries: ReadonlyArray<CustomModelEntry>): void;
|
|
212
215
|
setModelIdleTimeout(ms: number): void;
|
|
213
216
|
previewModelSource(context: PreviewModelSourceContext): Promise<ModelSourcePreview>;
|
|
217
|
+
private _assessFit;
|
|
214
218
|
describe(): Promise<HarnessInfo>;
|
|
215
219
|
diagnostics(): HarnessDiagnostics;
|
|
216
220
|
private _loadedModels;
|
|
@@ -261,6 +265,16 @@ export declare class Harness extends ReadyResource {
|
|
|
261
265
|
capability(): Promise<CapabilityInfo>;
|
|
262
266
|
warmModel(context: WarmModelOptions): Promise<void>;
|
|
263
267
|
private _warmModel;
|
|
268
|
+
loadModel(context: WarmModelOptions): Promise<LoadModelResult>;
|
|
269
|
+
private _loadModel;
|
|
270
|
+
unloadModel(context: UnloadModelContext): Promise<UnloadModelResult>;
|
|
271
|
+
private _unloadModel;
|
|
272
|
+
private _loadAndRelease;
|
|
273
|
+
private _unloadIdleGenerators;
|
|
274
|
+
private _fits;
|
|
275
|
+
private _yieldPins;
|
|
276
|
+
private _residency;
|
|
277
|
+
private _completionLoadOptions;
|
|
264
278
|
invoke(context: InvokeContext): AsyncGenerator<CompletionEvent>;
|
|
265
279
|
private _invoke;
|
|
266
280
|
completion(context: CompletionContext): AsyncGenerator<CompletionEvent>;
|