@qvac/harness 0.7.0 → 1.0.0-rc.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 (204) hide show
  1. package/CHANGELOG.md +42 -1
  2. package/README.md +239 -2
  3. package/dist-lib/index.d.ts +58 -3
  4. package/dist-lib/index.js +736 -239
  5. package/dist-lib/lib/capabilities/completion-engine/abort-polyfill.d.ts +1 -0
  6. package/dist-lib/lib/capabilities/completion-engine/abort-polyfill.js +10 -0
  7. package/dist-lib/lib/capabilities/completion-engine/actors/answering.d.ts +3 -0
  8. package/dist-lib/lib/capabilities/completion-engine/actors/answering.js +17 -0
  9. package/dist-lib/lib/capabilities/completion-engine/actors/approval.d.ts +4 -0
  10. package/dist-lib/lib/capabilities/completion-engine/actors/approval.js +29 -0
  11. package/dist-lib/lib/capabilities/completion-engine/actors/direct-search.d.ts +4 -0
  12. package/dist-lib/lib/capabilities/completion-engine/actors/direct-search.js +73 -0
  13. package/dist-lib/lib/capabilities/completion-engine/actors/execute.d.ts +41 -0
  14. package/dist-lib/lib/capabilities/completion-engine/actors/execute.js +49 -0
  15. package/dist-lib/lib/capabilities/completion-engine/actors/executing.d.ts +3 -0
  16. package/dist-lib/lib/capabilities/completion-engine/actors/executing.js +102 -0
  17. package/dist-lib/lib/capabilities/completion-engine/actors/execution-plan.d.ts +47 -0
  18. package/dist-lib/lib/capabilities/completion-engine/actors/execution-plan.js +87 -0
  19. package/dist-lib/lib/capabilities/completion-engine/actors/finishing.d.ts +2 -0
  20. package/dist-lib/lib/capabilities/completion-engine/actors/finishing.js +32 -0
  21. package/dist-lib/lib/capabilities/completion-engine/actors/inspect-preload.d.ts +3 -0
  22. package/dist-lib/lib/capabilities/completion-engine/actors/inspect-preload.js +75 -0
  23. package/dist-lib/lib/capabilities/completion-engine/actors/inspecting.d.ts +3 -0
  24. package/dist-lib/lib/capabilities/completion-engine/actors/inspecting.js +152 -0
  25. package/dist-lib/lib/capabilities/completion-engine/actors/loading-skill.d.ts +3 -0
  26. package/dist-lib/lib/capabilities/completion-engine/actors/loading-skill.js +94 -0
  27. package/dist-lib/lib/capabilities/completion-engine/actors/preload-failure.d.ts +9 -0
  28. package/dist-lib/lib/capabilities/completion-engine/actors/preload-failure.js +11 -0
  29. package/dist-lib/lib/capabilities/completion-engine/actors/preloading.d.ts +3 -0
  30. package/dist-lib/lib/capabilities/completion-engine/actors/preloading.js +114 -0
  31. package/dist-lib/lib/capabilities/completion-engine/actors/preparing.d.ts +3 -0
  32. package/dist-lib/lib/capabilities/completion-engine/actors/preparing.js +198 -0
  33. package/dist-lib/lib/capabilities/completion-engine/actors/rejecting.d.ts +3 -0
  34. package/dist-lib/lib/capabilities/completion-engine/actors/rejecting.js +71 -0
  35. package/dist-lib/lib/capabilities/completion-engine/actors/rejection.d.ts +18 -0
  36. package/dist-lib/lib/capabilities/completion-engine/actors/rejection.js +70 -0
  37. package/dist-lib/lib/capabilities/completion-engine/actors/resolving.d.ts +3 -0
  38. package/dist-lib/lib/capabilities/completion-engine/actors/resolving.js +60 -0
  39. package/dist-lib/lib/capabilities/completion-engine/actors/stream.d.ts +21 -0
  40. package/dist-lib/lib/capabilities/completion-engine/actors/stream.js +48 -0
  41. package/dist-lib/lib/capabilities/completion-engine/actors/streaming.d.ts +3 -0
  42. package/dist-lib/lib/capabilities/completion-engine/actors/streaming.js +156 -0
  43. package/dist-lib/lib/capabilities/completion-engine/actors/wrap-up.d.ts +7 -0
  44. package/dist-lib/lib/capabilities/completion-engine/actors/wrap-up.js +61 -0
  45. package/dist-lib/lib/capabilities/completion-engine/driver.d.ts +25 -0
  46. package/dist-lib/lib/capabilities/completion-engine/driver.js +553 -0
  47. package/dist-lib/lib/capabilities/completion-engine/durable.d.ts +61 -0
  48. package/dist-lib/lib/capabilities/completion-engine/durable.js +150 -0
  49. package/dist-lib/lib/capabilities/completion-engine/operations.d.ts +6 -0
  50. package/dist-lib/lib/capabilities/completion-engine/operations.js +239 -0
  51. package/dist-lib/lib/capabilities/completion-engine/ports.d.ts +3 -0
  52. package/dist-lib/lib/capabilities/completion-engine/ports.js +267 -0
  53. package/dist-lib/lib/capabilities/completion-engine/session.d.ts +76 -0
  54. package/dist-lib/lib/capabilities/completion-engine/session.js +70 -0
  55. package/dist-lib/lib/capabilities/completion-loop/index.d.ts +80 -0
  56. package/dist-lib/lib/capabilities/completion-loop/index.js +158 -0
  57. package/dist-lib/lib/capabilities/completion-loop/metrics.d.ts +5 -0
  58. package/dist-lib/lib/capabilities/completion-loop/metrics.js +29 -0
  59. package/dist-lib/lib/capabilities/completion-loop/round.d.ts +33 -0
  60. package/dist-lib/lib/capabilities/completion-loop/round.js +353 -0
  61. package/dist-lib/lib/capabilities/completion-loop/tool-execution.d.ts +60 -0
  62. package/dist-lib/lib/capabilities/completion-loop/tool-execution.js +270 -0
  63. package/dist-lib/lib/capabilities/completion-loop/turns.d.ts +23 -0
  64. package/dist-lib/lib/capabilities/completion-loop/turns.js +112 -0
  65. package/dist-lib/lib/capabilities/completion-runtime.d.ts +46 -0
  66. package/dist-lib/lib/capabilities/completion-runtime.js +74 -0
  67. package/dist-lib/lib/capabilities/completion.d.ts +18 -335
  68. package/dist-lib/lib/capabilities/completion.js +20 -1301
  69. package/dist-lib/lib/capabilities/download.d.ts +1 -1
  70. package/dist-lib/lib/capabilities/download.js +7 -2
  71. package/dist-lib/lib/capabilities/invoke.js +5 -3
  72. package/dist-lib/lib/capabilities/tool-plan.d.ts +35 -0
  73. package/dist-lib/lib/capabilities/tool-plan.js +66 -0
  74. package/dist-lib/lib/capabilities/tool-turns.d.ts +11 -2
  75. package/dist-lib/lib/capabilities/tool-turns.js +30 -2
  76. package/dist-lib/lib/capabilities/types.d.ts +287 -0
  77. package/dist-lib/lib/capabilities/types.js +1 -0
  78. package/dist-lib/lib/completion-lifecycle.d.ts +14 -0
  79. package/dist-lib/lib/completion-lifecycle.js +126 -0
  80. package/dist-lib/lib/connect.d.ts +10 -3
  81. package/dist-lib/lib/connect.js +329 -23
  82. package/dist-lib/lib/contract-types.d.ts +19 -2
  83. package/dist-lib/lib/harness-lifecycle.d.ts +66 -0
  84. package/dist-lib/lib/harness-lifecycle.js +129 -0
  85. package/dist-lib/lib/helpers/detach-json.d.ts +1 -0
  86. package/dist-lib/lib/helpers/detach-json.js +146 -0
  87. package/dist-lib/lib/helpers/markup-scanner.d.ts +26 -0
  88. package/dist-lib/lib/helpers/markup-scanner.js +156 -0
  89. package/dist-lib/lib/helpers/markup-stream-filter.js +138 -35
  90. package/dist-lib/lib/helpers/race-abort.d.ts +9 -4
  91. package/dist-lib/lib/helpers/race-abort.js +2 -7
  92. package/dist-lib/lib/helpers/recovery-required.d.ts +1 -0
  93. package/dist-lib/lib/helpers/recovery-required.js +1 -0
  94. package/dist-lib/lib/helpers/run-outcome.d.ts +10 -2
  95. package/dist-lib/lib/helpers/run-outcome.js +8 -5
  96. package/dist-lib/lib/helpers/tool-call-markup.d.ts +2 -0
  97. package/dist-lib/lib/helpers/tool-call-markup.js +197 -82
  98. package/dist-lib/lib/hooks/built-in/arg-repair.d.ts +1 -0
  99. package/dist-lib/lib/hooks/built-in/arg-repair.js +1 -0
  100. package/dist-lib/lib/hooks/built-in/egress.d.ts +1 -0
  101. package/dist-lib/lib/hooks/built-in/egress.js +2 -1
  102. package/dist-lib/lib/hooks/built-in/sandbox.d.ts +1 -0
  103. package/dist-lib/lib/hooks/built-in/sandbox.js +6 -1
  104. package/dist-lib/lib/hooks/built-in/skill-catalog.d.ts +1 -0
  105. package/dist-lib/lib/hooks/built-in/skill-catalog.js +2 -1
  106. package/dist-lib/lib/hooks/pipeline.d.ts +4 -1
  107. package/dist-lib/lib/hooks/pipeline.js +24 -2
  108. package/dist-lib/lib/hooks/run.d.ts +2 -1
  109. package/dist-lib/lib/hooks/run.js +19 -7
  110. package/dist-lib/lib/hooks/types.d.ts +17 -6
  111. package/dist-lib/lib/machine/completion/actions/approval.d.ts +3 -0
  112. package/dist-lib/lib/machine/completion/actions/approval.js +16 -0
  113. package/dist-lib/lib/machine/completion/actions/completion.d.ts +23 -0
  114. package/dist-lib/lib/machine/completion/actions/completion.js +142 -0
  115. package/dist-lib/lib/machine/completion/actions/skills.d.ts +9 -0
  116. package/dist-lib/lib/machine/completion/actions/skills.js +83 -0
  117. package/dist-lib/lib/machine/completion/actions/tools.d.ts +16 -0
  118. package/dist-lib/lib/machine/completion/actions/tools.js +173 -0
  119. package/dist-lib/lib/machine/completion/context.d.ts +9 -0
  120. package/dist-lib/lib/machine/completion/context.js +44 -0
  121. package/dist-lib/lib/machine/completion/contract.d.ts +6 -0
  122. package/dist-lib/lib/machine/completion/contract.js +1 -0
  123. package/dist-lib/lib/machine/completion/guards/retry.d.ts +9 -0
  124. package/dist-lib/lib/machine/completion/guards/retry.js +25 -0
  125. package/dist-lib/lib/machine/completion/implementations.d.ts +81 -0
  126. package/dist-lib/lib/machine/completion/implementations.js +152 -0
  127. package/dist-lib/lib/machine/completion/machine.d.ts +375 -0
  128. package/dist-lib/lib/machine/completion/machine.js +511 -0
  129. package/dist-lib/lib/machine/completion/ports.d.ts +65 -0
  130. package/dist-lib/lib/machine/completion/ports.js +224 -0
  131. package/dist-lib/lib/machine/completion/rules.d.ts +39 -0
  132. package/dist-lib/lib/machine/completion/rules.js +115 -0
  133. package/dist-lib/lib/machine/completion/types.d.ts +493 -0
  134. package/dist-lib/lib/machine/completion/types.js +1 -0
  135. package/dist-lib/lib/machine/engine.d.ts +93 -0
  136. package/dist-lib/lib/machine/engine.js +483 -0
  137. package/dist-lib/lib/machine/errors.d.ts +44 -0
  138. package/dist-lib/lib/machine/errors.js +373 -0
  139. package/dist-lib/lib/machine/guards.d.ts +2 -0
  140. package/dist-lib/lib/machine/guards.js +6 -0
  141. package/dist-lib/lib/machine/index.d.ts +20 -0
  142. package/dist-lib/lib/machine/index.js +11 -0
  143. package/dist-lib/lib/machine/replay-output.d.ts +24 -0
  144. package/dist-lib/lib/machine/replay-output.js +50 -0
  145. package/dist-lib/lib/machine/stable-stringify.d.ts +1 -0
  146. package/dist-lib/lib/machine/stable-stringify.js +11 -0
  147. package/dist-lib/lib/models/model-handle.d.ts +5 -1
  148. package/dist-lib/lib/models/model-handle.js +8 -3
  149. package/dist-lib/lib/models/model-list.d.ts +5 -3
  150. package/dist-lib/lib/models/model-pool.d.ts +18 -7
  151. package/dist-lib/lib/models/model-pool.js +126 -38
  152. package/dist-lib/lib/run-log/history-codec.d.ts +23 -0
  153. package/dist-lib/lib/run-log/history-codec.js +973 -0
  154. package/dist-lib/lib/run-log/patch.d.ts +6 -0
  155. package/dist-lib/lib/run-log/patch.js +93 -0
  156. package/dist-lib/lib/run-log/persisted-actor.d.ts +18 -0
  157. package/dist-lib/lib/run-log/persisted-actor.js +218 -0
  158. package/dist-lib/lib/run-log/protocol-types.d.ts +153 -0
  159. package/dist-lib/lib/run-log/protocol-types.js +1 -0
  160. package/dist-lib/lib/run-log/protocol.d.ts +27 -0
  161. package/dist-lib/lib/run-log/protocol.js +1056 -0
  162. package/dist-lib/lib/run-log/replay.d.ts +25 -0
  163. package/dist-lib/lib/run-log/replay.js +129 -0
  164. package/dist-lib/lib/run-log/run-journal.d.ts +125 -0
  165. package/dist-lib/lib/run-log/run-journal.js +783 -0
  166. package/dist-lib/lib/run-log-inspect.d.ts +25 -0
  167. package/dist-lib/lib/run-log-inspect.js +627 -0
  168. package/dist-lib/lib/run-log-protocol.d.ts +2 -0
  169. package/dist-lib/lib/run-log-protocol.js +1 -0
  170. package/dist-lib/lib/run-log-redact.d.ts +27 -0
  171. package/dist-lib/lib/run-log-redact.js +1107 -0
  172. package/dist-lib/lib/serve.js +308 -12
  173. package/dist-lib/lib/spawn.js +3 -2
  174. package/dist-lib/lib/tool-call-display.d.ts +1 -21
  175. package/dist-lib/lib/tools/exec.d.ts +2 -1
  176. package/dist-lib/lib/tools/exec.js +57 -2
  177. package/dist-lib/lib/tools/generate-image.js +1 -1
  178. package/dist-lib/lib/tools/generate-music.js +1 -1
  179. package/dist-lib/lib/tools/http-request.d.ts +2 -1
  180. package/dist-lib/lib/tools/http-request.js +2 -1
  181. package/dist-lib/lib/tools/mcp-call.js +8 -1
  182. package/dist-lib/lib/tools/operations/builders.d.ts +1 -0
  183. package/dist-lib/lib/tools/operations/builders.js +1 -0
  184. package/dist-lib/lib/tools/operations/compile.js +11 -1
  185. package/dist-lib/lib/tools/operations/manifest.js +1 -0
  186. package/dist-lib/lib/tools/outbound-guard.d.ts +8 -6
  187. package/dist-lib/lib/tools/outbound-guard.js +25 -8
  188. package/dist-lib/lib/tools/skills/catalog.d.ts +1 -0
  189. package/dist-lib/lib/tools/skills/catalog.js +35 -0
  190. package/dist-lib/lib/tools/skills/cli-schema-types.d.ts +1 -0
  191. package/dist-lib/lib/tools/skills/cli-schema.js +25 -0
  192. package/dist-lib/lib/wire.d.ts +5 -0
  193. package/dist-lib/lib/wire.js +128 -5
  194. package/dist-lib/schema/harness.js +22 -6
  195. package/dist-lib/spec/hrpc/messages.js +100 -18
  196. package/dist-lib/spec/hyperschema/index.js +100 -18
  197. package/dist-lib/spec/hyperschema/schema.json +74 -1
  198. package/dist-lib/spec/hyperschema/types.d.ts +11 -3
  199. package/package.json +19 -1
  200. package/patches/@qvac%2Finference@0.20.0.patch +67 -0
  201. package/patches/bare-stow@0.1.5.patch +68 -0
  202. package/patches/hypercore-blob-server@1.15.0.patch +15 -0
  203. package/patches/localwatch@1.4.3.patch +13 -0
  204. package/patches/pyodide@314.0.2.patch +144 -0
@@ -6,28 +6,42 @@ import { defaultContextSize } from './context.js';
6
6
  import { customContextLength } from './model-catalog.js';
7
7
  import { adrenoSafeKvCache } from './kv-cache.js';
8
8
  import { DEFAULT_EMBED_BATCH_SIZE } from './embed-config.js';
9
+ import { errorMessage } from '../guards.js';
9
10
  import { hlog } from '../log.js';
10
11
  import { RUNAWAY_STOP_SEQUENCES } from '../helpers/control-tokens.js';
11
12
  import { raceTimeout } from '../helpers/race-timeout.js';
12
13
  import { resolveModelSrc } from './model-source.js';
14
+ export class ModelUnloadError extends Error {
15
+ constructor(cause) {
16
+ super(errorMessage(cause));
17
+ this.name = 'ModelUnloadError';
18
+ }
19
+ }
13
20
  export function createLoadTracker() {
14
21
  const inflight = new Set();
15
- let draining = null;
22
+ let draining = false;
23
+ let drainSdk = null;
16
24
  const cancel = (sdk, requestId) => {
25
+ if (!sdk.cancel) {
26
+ return;
27
+ }
17
28
  void sdk.cancel({ requestId }).catch(noop);
18
29
  };
19
30
  return {
20
31
  get draining() {
21
- return draining !== null;
32
+ return draining;
22
33
  },
23
- track(pending) {
34
+ track(pending, sdk) {
24
35
  const { requestId } = pending;
25
36
  if (!requestId) {
26
37
  return pending;
27
38
  }
28
39
  if (draining) {
29
- cancel(draining, requestId);
30
- return pending;
40
+ const canceller = sdk ?? drainSdk;
41
+ if (canceller) {
42
+ cancel(canceller, requestId);
43
+ return pending;
44
+ }
31
45
  }
32
46
  inflight.add(requestId);
33
47
  const untrack = () => inflight.delete(requestId);
@@ -35,14 +49,21 @@ export function createLoadTracker() {
35
49
  return pending;
36
50
  },
37
51
  drain(sdk) {
38
- draining = sdk;
52
+ draining = true;
53
+ if (sdk) {
54
+ drainSdk = sdk;
55
+ }
56
+ if (!drainSdk) {
57
+ return;
58
+ }
39
59
  for (const requestId of inflight) {
40
- cancel(sdk, requestId);
60
+ cancel(drainSdk, requestId);
41
61
  }
42
62
  inflight.clear();
43
63
  },
44
64
  undrain() {
45
- draining = null;
65
+ draining = false;
66
+ drainSdk = null;
46
67
  }
47
68
  };
48
69
  }
@@ -88,9 +109,10 @@ export function releaseModel(pool, key) {
88
109
  void pending.then(() => releaseSettled(pool, key), () => releaseSettled(pool, key));
89
110
  }
90
111
  function releaseSettled(pool, key) {
91
- if (!pool.destroyed) {
92
- pool.release(key);
112
+ if (pool.destroyed) {
113
+ return;
93
114
  }
115
+ pool.release(key);
94
116
  }
95
117
  export function loadedModels(pool) {
96
118
  const out = [];
@@ -101,6 +123,34 @@ export function loadedModels(pool) {
101
123
  }
102
124
  return out;
103
125
  }
126
+ export function settledModels(pool) {
127
+ const out = [];
128
+ for (const entry of pool.resources.values()) {
129
+ if (entry.value.peek() !== null && !entry.value.loading) {
130
+ out.push(modelOf(entry.id));
131
+ }
132
+ }
133
+ return out;
134
+ }
135
+ export function loadingModels(pool) {
136
+ const out = [];
137
+ for (const entry of pool.resources.values()) {
138
+ if (entry.value.loading) {
139
+ out.push(modelOf(entry.id));
140
+ }
141
+ }
142
+ return out;
143
+ }
144
+ function reportedHandle(notify, model, load) {
145
+ return new ModelHandle({
146
+ load: () => {
147
+ notify({ status: 'loading', model, catalogChanged: true });
148
+ return load();
149
+ },
150
+ onLoaded: () => notify({ status: 'ready', model, catalogChanged: true }),
151
+ onFailed: (err) => notify({ status: 'error', model, message: errorMessage(err), catalogChanged: true })
152
+ });
153
+ }
104
154
  export async function leaseResidentModel(pool, wanted = () => true) {
105
155
  for (const entry of pool.resources.values()) {
106
156
  const key = entry.id;
@@ -289,10 +339,16 @@ export function loadClockGuard(model, sdk, { now = () => Date.now(), monoMs = mo
289
339
  };
290
340
  return { race };
291
341
  }
292
- export function createModelPool(loadSdk, notify, { deviceConfig = {}, loads = createLoadTracker() } = {}) {
342
+ export async function resolveCtxSize(loadSdk, model, opts) {
343
+ if (opts.ctxSize) {
344
+ return opts.ctxSize;
345
+ }
346
+ const sdk = await loadSdk();
347
+ return defaultContextSize(await resolveModelSrc(sdk, model));
348
+ }
349
+ export function createModelPool(loadSdk, notify, { deviceConfig = {}, loads = createLoadTracker(), onUnloadFailure } = {}) {
293
350
  const load = async (model, opts) => {
294
351
  const sdk = await loadSdk();
295
- notify({ status: 'loading', model });
296
352
  const modelSrc = await resolveModelSrc(sdk, model);
297
353
  const resolved = resolveLoadOptions(opts, deviceConfig);
298
354
  const ctxSize = resolved.ctxSize || defaultContextSize(modelSrc, customContextLength(model));
@@ -330,21 +386,19 @@ export function createModelPool(loadSdk, notify, { deviceConfig = {}, loads = cr
330
386
  modelType: 'llamacpp-completion',
331
387
  modelConfig,
332
388
  onProgress: (progress) => notify(progressState(model, progress))
333
- })));
389
+ }), sdk));
334
390
  hlog('llm loaded', { model, loadMs: Date.now() - loadStarted });
335
- notify({ status: 'ready', model });
336
391
  return { model, modelId, ctxSize };
337
392
  };
338
393
  return new ModelPuddle({
339
- open: (key, model = key, opts = {}) => new ModelHandle({ load: () => load(model, opts) }),
340
- gc: unloadOnGc(loadSdk, notify),
394
+ open: (key, model = key, opts = {}) => reportedHandle(notify, model, () => load(model, opts)),
395
+ gc: unloadOnGc(loadSdk, notify, onUnloadFailure),
341
396
  ...NO_IDLE_GC
342
397
  });
343
398
  }
344
- export function createEmbedPool(loadSdk, notify, { faults, batchSize = DEFAULT_EMBED_BATCH_SIZE, openclCacheDir, loads = createLoadTracker() }) {
399
+ export function createEmbedPool(loadSdk, notify, { faults, batchSize = DEFAULT_EMBED_BATCH_SIZE, openclCacheDir, loads = createLoadTracker(), onUnloadFailure }) {
345
400
  const load = async (model) => {
346
401
  const sdk = await loadSdk();
347
- notify({ status: 'loading', model });
348
402
  const modelSrc = await resolveModelSrc(sdk, model, 'embeddings');
349
403
  const openclCache = faults.device !== 'cpu' && openclCacheDir ? openclCacheDir() : undefined;
350
404
  const modelId = await loadClockGuard(model, sdk).race(loads.track(sdk.loadModel({
@@ -357,22 +411,20 @@ export function createEmbedPool(loadSdk, notify, { faults, batchSize = DEFAULT_E
357
411
  openclCacheDir: openclCache || undefined
358
412
  },
359
413
  onProgress: (progress) => notify(progressState(model, progress))
360
- })));
361
- notify({ status: 'ready', model });
414
+ }), sdk));
362
415
  return { model, modelId };
363
416
  };
364
417
  return new ModelPuddle({
365
- open: (key, model = key) => new ModelHandle({ load: () => load(model) }),
366
- gc: unloadOnGc(loadSdk, notify),
418
+ open: (key, model = key) => reportedHandle(notify, model, () => load(model)),
419
+ gc: unloadOnGc(loadSdk, notify, onUnloadFailure),
367
420
  ...NO_IDLE_GC
368
421
  });
369
422
  }
370
- export function createVoicePool(loadSdk, notify, { modelType, addon, modelConfig, openclCacheDir, loads = createLoadTracker() }) {
423
+ export function createVoicePool(loadSdk, notify, { modelType, addon, modelConfig, openclCacheDir, loads = createLoadTracker(), onUnloadFailure }) {
371
424
  const wantsGpu = modelConfig?.['useGPU'] === true;
372
425
  let gpuRefused = false;
373
426
  const load = async (model) => {
374
427
  const sdk = await loadSdk();
375
- notify({ status: 'loading', model });
376
428
  const modelSrc = await resolveModelSrc(sdk, model, addon);
377
429
  const attempt = () => {
378
430
  const config = gpuRefused ? { ...modelConfig, useGPU: false } : modelConfig;
@@ -382,7 +434,7 @@ export function createVoicePool(loadSdk, notify, { modelType, addon, modelConfig
382
434
  modelType,
383
435
  modelConfig: openclCache ? { openclCacheDir: openclCache, ...config } : config,
384
436
  onProgress: (progress) => notify(progressState(model, progress))
385
- }));
437
+ }), sdk);
386
438
  };
387
439
  const modelId = await loadClockGuard(model, sdk).race(attempt().catch((err) => {
388
440
  if (!wantsGpu || gpuRefused || loads.draining)
@@ -391,39 +443,75 @@ export function createVoicePool(loadSdk, notify, { modelType, addon, modelConfig
391
443
  gpuRefused = true;
392
444
  return attempt();
393
445
  }));
394
- notify({ status: 'ready', model });
395
446
  return { model, modelId };
396
447
  };
397
448
  return new ModelPuddle({
398
- open: (key, model = key) => new ModelHandle({ load: () => load(model) }),
399
- gc: unloadOnGc(loadSdk, notify),
449
+ open: (key, model = key) => reportedHandle(notify, model, () => load(model)),
450
+ gc: unloadOnGc(loadSdk, notify, onUnloadFailure),
400
451
  ...NO_IDLE_GC
401
452
  });
402
453
  }
403
- function unloadOnGc(loadSdk, notify) {
454
+ function unloadOnGc(loadSdk, notify, onUnloadFailure) {
404
455
  return async (handles) => {
405
- const sdk = await loadSdk();
456
+ const loadedHandles = [];
406
457
  for (const handle of handles) {
407
458
  const pending = handle.peek();
408
459
  if (pending === null) {
409
460
  continue;
410
461
  }
411
- let loaded;
412
462
  try {
413
- loaded = await pending;
463
+ loadedHandles.push(await pending);
414
464
  }
415
- catch {
416
- continue;
465
+ catch { }
466
+ }
467
+ if (loadedHandles.length === 0) {
468
+ return;
469
+ }
470
+ const reportFailure = (modelId, error) => {
471
+ try {
472
+ onUnloadFailure?.(modelId, error);
473
+ }
474
+ catch (callbackError) {
475
+ hlog('model unload failure observer failed', { error: String(callbackError) });
476
+ }
477
+ };
478
+ let sdk;
479
+ try {
480
+ sdk = await loadSdk();
481
+ }
482
+ catch (error) {
483
+ for (const { modelId } of loadedHandles) {
484
+ reportFailure(modelId, error);
485
+ }
486
+ throw new ModelUnloadError(error);
487
+ }
488
+ let unloadError;
489
+ let unloadFailed = false;
490
+ for (const { model, modelId } of loadedHandles) {
491
+ try {
492
+ notify({ status: 'unloading', model });
493
+ }
494
+ catch (error) {
495
+ hlog('model unloading observer failed', { error: String(error) });
417
496
  }
418
- const { model, modelId } = loaded;
419
- notify({ status: 'unloading', model });
420
497
  try {
421
498
  await sdk.unloadModel({ modelId });
422
499
  }
423
- catch {
500
+ catch (error) {
501
+ unloadError ??= error;
502
+ unloadFailed = true;
503
+ reportFailure(modelId, error);
424
504
  continue;
425
505
  }
426
- notify({ status: 'unloaded', model });
506
+ try {
507
+ notify({ status: 'unloaded', model, catalogChanged: true });
508
+ }
509
+ catch (error) {
510
+ hlog('model unloaded observer failed', { error: String(error) });
511
+ }
512
+ }
513
+ if (unloadFailed) {
514
+ throw new ModelUnloadError(unloadError);
427
515
  }
428
516
  };
429
517
  }
@@ -0,0 +1,23 @@
1
+ import { type Patch } from './patch.ts';
2
+ export type { HistoryReference } from './protocol-types.ts';
3
+ export interface HistoryProjectionOptions {
4
+ base: readonly unknown[] | undefined;
5
+ failureRefs?: ReadonlySet<string>;
6
+ validateFailureOutputs?: boolean;
7
+ validate?: boolean;
8
+ }
9
+ export declare const FAILURE_RESULT_REF_MACHINE_VERSION = 8;
10
+ export declare function requestMessages(request: unknown): readonly unknown[] | undefined;
11
+ export declare function compactSnapshotHistory<Value>(snapshot: Value, base: readonly unknown[] | undefined): Value;
12
+ export declare function materializeSnapshotHistory<Value>(snapshot: Value, base: readonly unknown[] | undefined, allowLegacyInlineFailureResults?: boolean): Value;
13
+ export declare function compactMachineEvent<Value>(event: Value, base: readonly unknown[] | undefined): Value;
14
+ export declare function materializeMachineEvent<Value>(event: Value, base: readonly unknown[] | undefined): Value;
15
+ export interface SnapshotHistoryValidationOptions {
16
+ allowLegacyInlineFailureResults?: boolean;
17
+ validateMachineContext?: boolean;
18
+ }
19
+ export declare function validateSnapshotHistory(snapshot: unknown, base: readonly unknown[] | undefined, options?: SnapshotHistoryValidationOptions): void;
20
+ export declare function snapshotFailureResultRefs(snapshot: unknown, allowLegacyInlineFailureResults?: boolean): ReadonlySet<string>;
21
+ export declare function validateMachineEventHistory(event: unknown, base: readonly unknown[] | undefined, failureRefs?: ReadonlySet<string>): void;
22
+ export declare function foldMachineEventHistory(previous: unknown, patch: Patch, options: HistoryProjectionOptions): unknown;
23
+ export declare function validateHistoryProjection(value: unknown, options: HistoryProjectionOptions): void;