@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.
Files changed (68) hide show
  1. package/CHANGELOG.md +142 -1
  2. package/README.md +78 -27
  3. package/dist-lib/index.d.ts +15 -1
  4. package/dist-lib/index.js +175 -53
  5. package/dist-lib/lib/capabilities/preview-model-source.d.ts +0 -1
  6. package/dist-lib/lib/connect.d.ts +3 -1
  7. package/dist-lib/lib/connect.js +23 -2
  8. package/dist-lib/lib/contract-types.d.ts +14 -0
  9. package/dist-lib/lib/docx/index.d.ts +1 -1
  10. package/dist-lib/lib/docx/index.js +1 -1
  11. package/dist-lib/lib/hardware/capability-probe.js +9 -4
  12. package/dist-lib/lib/hooks/built-in/sandbox.js +0 -5
  13. package/dist-lib/lib/models/model-catalog-constants.d.ts +7 -0
  14. package/dist-lib/lib/models/model-catalog-constants.js +17 -0
  15. package/dist-lib/lib/models/model-catalog.d.ts +16 -6
  16. package/dist-lib/lib/models/model-catalog.js +21 -6
  17. package/dist-lib/lib/models/model-list.d.ts +2 -0
  18. package/dist-lib/lib/models/model-list.js +9 -4
  19. package/dist-lib/lib/models/model-pool.d.ts +6 -2
  20. package/dist-lib/lib/models/model-pool.js +67 -11
  21. package/dist-lib/lib/models/model-task.d.ts +3 -0
  22. package/dist-lib/lib/models/model-task.js +14 -0
  23. package/dist-lib/lib/models/music-catalog.d.ts +2 -0
  24. package/dist-lib/lib/models/music-catalog.js +9 -0
  25. package/dist-lib/lib/office/index.d.ts +1 -1
  26. package/dist-lib/lib/office/index.js +1 -1
  27. package/dist-lib/lib/office/python.js +1 -2
  28. package/dist-lib/lib/serve.js +12 -0
  29. package/dist-lib/lib/tools/exec/adapters/python/deadline-state.d.ts +10 -0
  30. package/dist-lib/lib/tools/exec/adapters/python/deadline-state.js +5 -0
  31. package/dist-lib/lib/tools/exec/adapters/python/interrupt-timer.js +10 -17
  32. package/dist-lib/lib/tools/exec/adapters/python/loader.js +15 -11
  33. package/dist-lib/lib/tools/exec/adapters/python/pyodide.js +1 -15
  34. package/dist-lib/lib/tools/exec/adapters/python/python-adapter.d.ts +1 -0
  35. package/dist-lib/lib/tools/exec/adapters/python/python-adapter.js +13 -2
  36. package/dist-lib/lib/tools/exec/adapters/python/wheels.d.ts +3 -3
  37. package/dist-lib/lib/tools/exec/adapters/python/wheels.js +3 -14
  38. package/dist-lib/lib/tools/exec/adapters/python/worker/active.d.ts +19 -0
  39. package/dist-lib/lib/tools/exec/adapters/python/worker/active.js +72 -0
  40. package/dist-lib/lib/tools/exec/adapters/python/worker/client.d.ts +0 -1
  41. package/dist-lib/lib/tools/exec/adapters/python/worker/client.js +8 -76
  42. package/dist-lib/lib/tools/exec/adapters/python/worker/entry.js +2 -126
  43. package/dist-lib/lib/tools/exec/adapters/python/worker/interrupt-deadline.d.ts +1 -0
  44. package/dist-lib/lib/tools/exec/adapters/python/worker/interrupt-deadline.js +21 -0
  45. package/dist-lib/lib/tools/exec/adapters/python/worker/serve.d.ts +2 -0
  46. package/dist-lib/lib/tools/exec/adapters/python/worker/serve.js +90 -0
  47. package/dist-lib/lib/tools/exec/adapters/python/worker/{spawn-node.d.ts → spawn.d.ts} +0 -1
  48. package/dist-lib/lib/tools/exec/adapters/python/worker/{spawn-node.js → spawn.js} +0 -8
  49. package/dist-lib/lib/tools/exec/bare-runtime.d.ts +2 -0
  50. package/dist-lib/lib/tools/exec/bare-runtime.js +10 -0
  51. package/dist-lib/lib/tools/exec.d.ts +0 -2
  52. package/dist-lib/lib/tools/exec.js +6 -11
  53. package/dist-lib/schema/harness.js +27 -1
  54. package/dist-lib/spec/bind.js +6 -0
  55. package/dist-lib/spec/calls.js +2 -0
  56. package/dist-lib/spec/hrpc/hrpc.json +26 -0
  57. package/dist-lib/spec/hrpc/index.js +27 -3
  58. package/dist-lib/spec/hrpc/messages.js +72 -5
  59. package/dist-lib/spec/hyperschema/index.js +72 -5
  60. package/dist-lib/spec/hyperschema/schema.json +53 -1
  61. package/dist-lib/spec/hyperschema/types.d.ts +18 -1
  62. package/package.json +40 -20
  63. package/dist/harness.bundle +0 -42312
  64. package/dist/harness.cjs +0 -18
  65. package/dist/harness.d.ts +0 -8
  66. package/dist/prebuilds-manifest.json +0 -372
  67. package/dist-lib/lib/tools/exec/adapters/python/worker/spawn-bare.d.ts +0 -3
  68. 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.5.0...HEAD
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 prebuilt engine and its runtime content, not
16
- the library source:
17
-
18
- - `dist/harness.bundle` — the stowed sidecar (all platforms in one bundle)
19
- - `dist/prebuilds-manifest.json` — every native prebuild dir the bundle defers,
20
- keyed by bundle-relative path; the host assembles those beside the bundle
21
- from its own `node_modules`
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
- The `@qvac` inference addons and `pyodide` resolve from the host's real
27
- `node_modules` at runtime (dlopen'd backends need real paths), so the host
28
- installs those alongside.
29
-
30
- The host-side library surface — `spawnHarness`/`harnessChild`, the transport,
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
- The generated `dist/harness.cjs` is the host entry: it spawns the bundle as a
38
- bare-sidecar process and hands back the stow ipc plus the exit promise.
35
+ `spawnHarness` spawns an entry as a bare-sidecar process and hands back a
36
+ client over hrpc:
39
37
 
40
38
  ```js
41
- const harness = require('@qvac/harness/dist/harness.cjs')
39
+ import { spawnHarness } from '@qvac/harness'
42
40
 
43
- const { ipc, sidecar, exit } = await harness.start(args)
41
+ const harness = spawnHarness({ entry, sdkStorage })
44
42
  ```
45
43
 
46
- The argv slots the bundle reads (skills dir, sdk storage, model config, wheels
47
- dir, ...) are the ones `worker/harness-sidecar.mjs` documents in this repo. The
48
- in-house hosts don't call this directly — they use the repo's library surface
49
- (`harnessChild` under bare-supervisor), which owns that argv contract.
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. Bundled hosts also set `QVAC_PYODIDE_WORKER_ENTRY` and
231
- `QVAC_PYTHON_WHEELS_DIR` to their staged worker and wheels paths.
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/harness.bundle (--minify for the shipped form)
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
@@ -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>;