@qvac/harness 0.3.3 → 0.5.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 +700 -126
- package/README.md +156 -0
- package/dist/harness.bundle +71 -103
- package/dist/prebuilds-manifest.json +0 -8
- package/dist-lib/index.d.ts +42 -40
- package/dist-lib/index.js +307 -117
- package/dist-lib/lib/audio-transcode-bare.d.ts +2 -2
- package/dist-lib/lib/audio-transcode-bare.js +28 -18
- package/dist-lib/lib/audio-transcode-node.d.ts +2 -2
- package/dist-lib/lib/capabilities/audio-resample.d.ts +7 -6
- package/dist-lib/lib/capabilities/audio-resample.js +30 -18
- package/dist-lib/lib/capabilities/completion.d.ts +20 -19
- package/dist-lib/lib/capabilities/completion.js +194 -135
- package/dist-lib/lib/capabilities/download.d.ts +6 -6
- package/dist-lib/lib/capabilities/download.js +15 -8
- package/dist-lib/lib/capabilities/embed.js +2 -1
- package/dist-lib/lib/capabilities/enhance.d.ts +6 -1
- package/dist-lib/lib/capabilities/enhance.js +7 -4
- package/dist-lib/lib/capabilities/invoke.js +7 -4
- package/dist-lib/lib/capabilities/kv-cache.js +2 -1
- package/dist-lib/lib/capabilities/preview-model-source.d.ts +69 -0
- package/dist-lib/lib/capabilities/preview-model-source.js +439 -0
- package/dist-lib/lib/capabilities/speech-text.js +5 -4
- package/dist-lib/lib/capabilities/tool-selection.js +10 -9
- package/dist-lib/lib/capabilities/tool-turns.js +30 -16
- package/dist-lib/lib/capabilities/usage-breakdown.js +2 -1
- package/dist-lib/lib/capabilities/voice.d.ts +5 -1
- package/dist-lib/lib/capabilities/voice.js +22 -12
- package/dist-lib/lib/connect.d.ts +15 -37
- package/dist-lib/lib/connect.js +161 -112
- package/dist-lib/lib/context-window.js +25 -21
- package/dist-lib/lib/contract-types.d.ts +26 -20
- package/dist-lib/lib/diagram-repair.d.ts +4 -4
- package/dist-lib/lib/diagram-repair.js +6 -3
- package/dist-lib/lib/docx/index.d.ts +3 -2
- package/dist-lib/lib/{error-fields.d.ts → guards.d.ts} +1 -0
- package/dist-lib/lib/{error-fields.js → guards.js} +3 -0
- package/dist-lib/lib/hardware/capability-probe.js +20 -10
- package/dist-lib/lib/hardware/gpu-classify.js +6 -3
- package/dist-lib/lib/hardware/gpu-probe-addon.js +8 -4
- package/dist-lib/lib/hardware/gpu-probe.js +4 -2
- package/dist-lib/lib/hardware/gpu-stats.native.cjs +8 -9
- package/dist-lib/lib/hardware/parsers.js +8 -4
- package/dist-lib/lib/helpers/buffer-burst.js +4 -2
- package/dist-lib/lib/helpers/control-tokens.js +4 -2
- package/dist-lib/lib/helpers/join-guard.d.ts +2 -2
- package/dist-lib/lib/helpers/join-guard.js +4 -2
- package/dist-lib/lib/helpers/load-stall.js +4 -2
- package/dist-lib/lib/helpers/markup-stream-filter.d.ts +2 -2
- package/dist-lib/lib/helpers/markup-stream-filter.js +6 -3
- package/dist-lib/lib/helpers/race-abort.js +2 -1
- package/dist-lib/lib/helpers/race-timeout.d.ts +5 -0
- package/dist-lib/lib/helpers/race-timeout.js +14 -0
- package/dist-lib/lib/helpers/run-outcome.d.ts +6 -8
- package/dist-lib/lib/helpers/run-outcome.js +36 -20
- package/dist-lib/lib/helpers/spawn-path.js +6 -3
- package/dist-lib/lib/helpers/text-coalescer.js +6 -3
- package/dist-lib/lib/helpers/thinking.js +38 -45
- package/dist-lib/lib/helpers/tool-call-markup.d.ts +9 -7
- package/dist-lib/lib/helpers/tool-call-markup.js +36 -20
- package/dist-lib/lib/helpers/tool-intent.d.ts +3 -2
- package/dist-lib/lib/helpers/tool-intent.js +4 -2
- package/dist-lib/lib/helpers/tool-label.js +18 -9
- package/dist-lib/lib/hooks/built-in/arg-repair.js +23 -13
- package/dist-lib/lib/hooks/built-in/egress.js +2 -1
- package/dist-lib/lib/hooks/built-in/skill-catalog.js +2 -1
- package/dist-lib/lib/hooks/pipeline.d.ts +5 -4
- package/dist-lib/lib/hooks/pipeline.js +6 -3
- package/dist-lib/lib/hooks/run.js +12 -8
- package/dist-lib/lib/model-download-progress.js +10 -8
- package/dist-lib/lib/models/context.d.ts +1 -1
- package/dist-lib/lib/models/context.js +5 -1
- package/dist-lib/lib/models/custom-model-cache.d.ts +13 -0
- package/dist-lib/lib/models/custom-model-cache.js +70 -0
- package/dist-lib/lib/models/gguf-header.d.ts +31 -0
- package/dist-lib/lib/models/gguf-header.js +230 -0
- package/dist-lib/lib/models/idle-unload.d.ts +14 -0
- package/dist-lib/lib/models/idle-unload.js +51 -0
- package/dist-lib/lib/models/kv-cache.d.ts +3 -2
- package/dist-lib/lib/models/kv-cache.js +4 -3
- package/dist-lib/lib/models/llm-presets.d.ts +2 -2
- package/dist-lib/lib/models/llm-presets.js +4 -2
- package/dist-lib/lib/models/model-catalog-constants.js +3 -2
- package/dist-lib/lib/models/model-catalog.d.ts +19 -21
- package/dist-lib/lib/models/model-catalog.js +66 -33
- package/dist-lib/lib/models/model-delete.d.ts +4 -1
- package/dist-lib/lib/models/model-delete.js +30 -15
- package/dist-lib/lib/models/model-handle.js +2 -1
- package/dist-lib/lib/models/model-list.d.ts +14 -3
- package/dist-lib/lib/models/model-list.js +33 -6
- package/dist-lib/lib/models/model-pool.d.ts +44 -10
- package/dist-lib/lib/models/model-pool.js +47 -42
- package/dist-lib/lib/models/model-source.js +11 -6
- package/dist-lib/lib/models/music-catalog.d.ts +2 -2
- package/dist-lib/lib/models/nmt-catalog.d.ts +4 -3
- package/dist-lib/lib/models/nmt-catalog.js +10 -5
- package/dist-lib/lib/models/opencl-cache.d.ts +6 -1
- package/dist-lib/lib/models/opencl-cache.js +5 -3
- package/dist-lib/lib/models/sdk-faults.d.ts +11 -8
- package/dist-lib/lib/models/sdk-faults.js +9 -6
- package/dist-lib/lib/models/shards.d.ts +11 -0
- package/dist-lib/lib/models/shards.js +15 -0
- package/dist-lib/lib/models/tool-dialect.js +10 -5
- package/dist-lib/lib/no-redirect-fetch-bare.d.ts +3 -3
- package/dist-lib/lib/no-redirect-fetch-bare.js +1 -1
- package/dist-lib/lib/no-redirect-fetch-impl.js +6 -3
- package/dist-lib/lib/no-redirect-fetch-node.d.ts +1 -1
- package/dist-lib/lib/no-redirect-fetch-node.js +9 -9
- package/dist-lib/lib/office/index.d.ts +3 -2
- package/dist-lib/lib/office/python.d.ts +3 -2
- package/dist-lib/lib/office/python.js +2 -1
- package/dist-lib/lib/prompt.d.ts +5 -4
- package/dist-lib/lib/prompt.js +8 -4
- package/dist-lib/lib/queue.js +10 -5
- package/dist-lib/lib/resolution-detector.js +21 -11
- package/dist-lib/lib/rpc-session.js +2 -1
- package/dist-lib/lib/sdk-loader.js +2 -1
- package/dist-lib/lib/sdk-storage.js +4 -2
- package/dist-lib/lib/serve.js +128 -68
- package/dist-lib/lib/spawn.js +7 -4
- package/dist-lib/lib/tmp-path.d.ts +7 -6
- package/dist-lib/lib/tool-call-display.d.ts +2 -2
- package/dist-lib/lib/tools/create-documents.js +18 -10
- package/dist-lib/lib/tools/edit-documents.js +23 -13
- package/dist-lib/lib/tools/edit-image.d.ts +2 -2
- package/dist-lib/lib/tools/edit-image.js +60 -36
- package/dist-lib/lib/tools/exec/adapters/adapter.d.ts +10 -10
- package/dist-lib/lib/tools/exec/adapters/python/attachments.d.ts +17 -11
- package/dist-lib/lib/tools/exec/adapters/python/attachments.js +53 -40
- package/dist-lib/lib/tools/exec/adapters/python/create-effect.d.ts +2 -2
- package/dist-lib/lib/tools/exec/adapters/python/create-effect.js +60 -32
- package/dist-lib/lib/tools/exec/adapters/python/guarded-fetch.d.ts +33 -22
- package/dist-lib/lib/tools/exec/adapters/python/guarded-fetch.js +58 -29
- package/dist-lib/lib/tools/exec/adapters/python/interrupt-timer.d.ts +2 -2
- package/dist-lib/lib/tools/exec/adapters/python/loader.js +23 -12
- package/dist-lib/lib/tools/exec/adapters/python/memfs.d.ts +13 -11
- package/dist-lib/lib/tools/exec/adapters/python/memfs.js +10 -5
- package/dist-lib/lib/tools/exec/adapters/python/net-shim.js +3 -1
- package/dist-lib/lib/tools/exec/adapters/python/output-policy.d.ts +6 -4
- package/dist-lib/lib/tools/exec/adapters/python/output-policy.js +20 -10
- package/dist-lib/lib/tools/exec/adapters/python/pyodide.d.ts +2 -2
- package/dist-lib/lib/tools/exec/adapters/python/pyodide.js +14 -7
- package/dist-lib/lib/tools/exec/adapters/python/python-adapter.d.ts +41 -34
- package/dist-lib/lib/tools/exec/adapters/python/python-adapter.js +316 -166
- package/dist-lib/lib/tools/exec/adapters/python/run-session.d.ts +9 -8
- package/dist-lib/lib/tools/exec/adapters/python/run-session.js +56 -28
- package/dist-lib/lib/tools/exec/adapters/python/wheels.d.ts +8 -10
- package/dist-lib/lib/tools/exec/adapters/python/wheels.js +22 -11
- package/dist-lib/lib/tools/exec/adapters/python/worker/client.d.ts +3 -2
- package/dist-lib/lib/tools/exec/adapters/python/worker/client.js +41 -26
- package/dist-lib/lib/tools/exec/adapters/python/worker/entry.js +27 -18
- package/dist-lib/lib/tools/exec/adapters/python/worker/protocol.d.ts +2 -2
- package/dist-lib/lib/tools/exec/adapters/python/worker/protocol.js +14 -13
- package/dist-lib/lib/tools/exec/adapters/python/worker/spawn-node.d.ts +4 -4
- package/dist-lib/lib/tools/exec/adapters/python/worker/spawn-node.js +10 -5
- package/dist-lib/lib/tools/exec/adapters/shell/shell-adapter.d.ts +4 -4
- package/dist-lib/lib/tools/exec/adapters/shell/shell-adapter.js +2 -1
- package/dist-lib/lib/tools/exec/obsidian/cli-process.d.ts +6 -1
- package/dist-lib/lib/tools/exec/obsidian/cli-process.js +8 -5
- package/dist-lib/lib/tools/exec/obsidian/cli.d.ts +6 -6
- package/dist-lib/lib/tools/exec/obsidian/cli.js +4 -4
- package/dist-lib/lib/tools/exec/obsidian/command.d.ts +3 -2
- package/dist-lib/lib/tools/exec/obsidian/command.js +6 -3
- package/dist-lib/lib/tools/exec/obsidian/output.js +2 -1
- package/dist-lib/lib/tools/exec/obsidian/route.d.ts +4 -6
- package/dist-lib/lib/tools/exec/obsidian/route.js +17 -11
- package/dist-lib/lib/tools/exec/obsidian/safe-path.js +2 -1
- package/dist-lib/lib/tools/exec/obsidian/vault-create.js +15 -7
- package/dist-lib/lib/tools/exec/obsidian/vault-paths.d.ts +2 -2
- package/dist-lib/lib/tools/exec/obsidian/vault-paths.js +20 -10
- package/dist-lib/lib/tools/exec/obsidian/vault-read.js +20 -13
- package/dist-lib/lib/tools/exec/obsidian/vault-write.js +24 -12
- package/dist-lib/lib/tools/exec/runner.d.ts +14 -14
- package/dist-lib/lib/tools/exec/runner.js +5 -3
- package/dist-lib/lib/tools/exec/scope.js +52 -28
- package/dist-lib/lib/tools/exec/shell-argv.js +31 -18
- package/dist-lib/lib/tools/exec/shell-guidance.d.ts +6 -1
- package/dist-lib/lib/tools/exec/shell-guidance.js +35 -20
- package/dist-lib/lib/tools/exec/video-tools.js +2 -2
- package/dist-lib/lib/tools/exec.d.ts +6 -8
- package/dist-lib/lib/tools/exec.js +113 -54
- package/dist-lib/lib/tools/file-glob.d.ts +4 -5
- package/dist-lib/lib/tools/file-glob.js +16 -11
- package/dist-lib/lib/tools/fs/glob.js +13 -18
- package/dist-lib/lib/tools/fs/remote-protocol.d.ts +10 -10
- package/dist-lib/lib/tools/fs/remote.d.ts +3 -2
- package/dist-lib/lib/tools/fs/remote.js +13 -7
- package/dist-lib/lib/tools/fs/scope.d.ts +8 -3
- package/dist-lib/lib/tools/fs/scope.js +20 -12
- package/dist-lib/lib/tools/fs/walk.js +6 -3
- package/dist-lib/lib/tools/fs/write.d.ts +3 -2
- package/dist-lib/lib/tools/generate-image.d.ts +11 -9
- package/dist-lib/lib/tools/generate-image.js +73 -37
- package/dist-lib/lib/tools/generate-music.d.ts +22 -11
- package/dist-lib/lib/tools/generate-music.js +79 -48
- package/dist-lib/lib/tools/grep.js +66 -41
- package/dist-lib/lib/tools/http-request/encode-fields.js +18 -9
- package/dist-lib/lib/tools/http-request/{utils.js → request.js} +20 -11
- package/dist-lib/lib/tools/http-request/truncate-response.js +57 -46
- package/dist-lib/lib/tools/http-request.d.ts +1 -1
- package/dist-lib/lib/tools/http-request.js +33 -18
- package/dist-lib/lib/tools/mcp/protocol.d.ts +53 -0
- package/dist-lib/lib/tools/mcp/{utils.js → protocol.js} +45 -23
- package/dist-lib/lib/tools/mcp-call.d.ts +1 -1
- package/dist-lib/lib/tools/mcp-call.js +37 -16
- package/dist-lib/lib/tools/operations/builders.js +10 -6
- package/dist-lib/lib/tools/operations/compile.js +20 -10
- package/dist-lib/lib/tools/operations/decoders.js +12 -6
- package/dist-lib/lib/tools/operations/gmail-message.js +3 -2
- package/dist-lib/lib/tools/outbound-guard.d.ts +4 -3
- package/dist-lib/lib/tools/outbound-guard.js +14 -8
- package/dist-lib/lib/tools/private-ip.js +8 -7
- package/dist-lib/lib/tools/rag-search.js +14 -7
- package/dist-lib/lib/tools/read-files.js +23 -20
- package/dist-lib/lib/tools/skill.js +19 -10
- package/dist-lib/lib/tools/skills/auth-resolver.d.ts +11 -18
- package/dist-lib/lib/tools/skills/auth-resolver.js +30 -18
- package/dist-lib/lib/tools/skills/bin-check.d.ts +3 -2
- package/dist-lib/lib/tools/skills/bin-check.js +10 -3
- package/dist-lib/lib/tools/skills/bundled-dir.js +20 -10
- package/dist-lib/lib/tools/skills/bundled-hash.d.ts +3 -2
- package/dist-lib/lib/tools/skills/bundled-hash.js +6 -1
- package/dist-lib/lib/tools/skills/catalog.d.ts +3 -2
- package/dist-lib/lib/tools/skills/catalog.js +33 -28
- package/dist-lib/lib/tools/skills/cli-argv.d.ts +3 -2
- package/dist-lib/lib/tools/skills/cli-argv.js +55 -52
- package/dist-lib/lib/tools/skills/cli-schema-check.js +21 -10
- package/dist-lib/lib/tools/skills/cli-schema-load.js +28 -20
- package/dist-lib/lib/tools/skills/cli-schema-types.d.ts +6 -6
- package/dist-lib/lib/tools/skills/cli-schema.js +2 -1
- package/dist-lib/lib/tools/skills/credential-check.d.ts +6 -3
- package/dist-lib/lib/tools/skills/credential-check.js +24 -12
- package/dist-lib/lib/tools/skills/credential-grants.js +1 -6
- package/dist-lib/lib/tools/skills/credential-health.d.ts +5 -1
- package/dist-lib/lib/tools/skills/credential-health.js +5 -3
- package/dist-lib/lib/tools/skills/frontmatter-parser.js +10 -5
- package/dist-lib/lib/tools/skills/manifest-parse.js +84 -64
- package/dist-lib/lib/tools/skills/mention.js +7 -6
- package/dist-lib/lib/tools/skills/obsidian-readiness.d.ts +2 -2
- package/dist-lib/lib/tools/skills/obsidian-readiness.js +11 -3
- package/dist-lib/lib/tools/skills/overlay-crud.d.ts +6 -4
- package/dist-lib/lib/tools/skills/overlay-crud.js +12 -6
- package/dist-lib/lib/tools/skills/overlay-dir.js +4 -2
- package/dist-lib/lib/tools/skills/overlay-watch.d.ts +3 -2
- package/dist-lib/lib/tools/skills/overlay-watch.js +8 -4
- package/dist-lib/lib/tools/skills/setup-routes.js +1 -3
- package/dist-lib/lib/tools/skills/skill-settings.js +4 -1
- package/dist-lib/lib/tools/skills/skill-state.d.ts +6 -11
- package/dist-lib/lib/tools/skills/skill-state.js +48 -29
- package/dist-lib/lib/tools/skills/tool-grants.js +6 -3
- package/dist-lib/lib/tools/toolsets.js +2 -1
- package/dist-lib/lib/tools/translate.d.ts +4 -5
- package/dist-lib/lib/tools/translate.js +31 -14
- package/dist-lib/lib/tools/url-guard.js +2 -1
- package/dist-lib/lib/tools/weather-lookup/place.js +8 -4
- package/dist-lib/lib/tools/weather-lookup/report.d.ts +7 -1
- package/dist-lib/lib/tools/weather-lookup/report.js +46 -9
- package/dist-lib/lib/tools/weather-lookup.js +18 -12
- package/dist-lib/lib/tools/web-fetch.js +47 -24
- package/dist-lib/lib/tools/web-search.js +8 -3
- package/dist-lib/lib/validating-lookup.d.ts +4 -4
- package/dist-lib/lib/wav-encode.d.ts +1 -1
- package/dist-lib/lib/wav-encode.js +11 -10
- package/dist-lib/lib/web-fetch/embedded-state.js +24 -12
- package/dist-lib/lib/web-fetch/extract.js +4 -2
- package/dist-lib/lib/web-fetch/images.js +8 -4
- package/dist-lib/lib/web-fetch/video.d.ts +2 -2
- package/dist-lib/lib/web-fetch/video.js +8 -4
- package/dist-lib/lib/web-search/engine-registry.d.ts +2 -2
- package/dist-lib/lib/web-search/engines/aol.js +1 -1
- package/dist-lib/lib/web-search/engines/bing.js +1 -1
- package/dist-lib/lib/web-search/engines/brave.js +4 -1
- package/dist-lib/lib/web-search/engines/duckduckgo.js +3 -2
- package/dist-lib/lib/web-search/engines/google.js +7 -3
- package/dist-lib/lib/web-search/engines/wikipedia.js +5 -4
- package/dist-lib/lib/web-search/engines/yahoo.js +1 -1
- package/dist-lib/lib/web-search/fetch-html.d.ts +5 -4
- package/dist-lib/lib/web-search/fetch-html.js +13 -7
- package/dist-lib/lib/web-search/orchestrator.d.ts +9 -5
- package/dist-lib/lib/web-search/orchestrator.js +3 -3
- package/dist-lib/lib/wire.d.ts +3 -2
- package/dist-lib/lib/wire.js +23 -15
- package/dist-lib/schema/baseline.js +10 -5
- package/dist-lib/schema/build.js +2 -1
- package/dist-lib/schema/harness.d.ts +15 -2
- package/dist-lib/schema/harness.js +55 -2
- package/dist-lib/schema/release-tags.d.ts +3 -2
- package/dist-lib/schema/release-tags.js +6 -3
- 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 +207 -8
- package/dist-lib/spec/hyperschema/index.js +207 -8
- package/dist-lib/spec/hyperschema/schema.json +165 -1
- package/dist-lib/spec/hyperschema/types.d.ts +42 -1
- package/package.json +13 -14
- package/worker/harness-sidecar.mjs +16 -22
- package/worker/stow-entry.mjs +7 -4
- package/dist-lib/lib/tools/mcp/utils.d.ts +0 -47
- /package/dist-lib/lib/tools/http-request/{utils.d.ts → request.d.ts} +0 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { raceTimeout } from '../helpers/race-timeout.js';
|
|
2
|
+
const DEFAULT_TICK_MS = 60_000;
|
|
3
|
+
export function createIdleReaper({ sweep, waitMs, onError, now = Date.now, tickMs = DEFAULT_TICK_MS }) {
|
|
4
|
+
let timeoutMs = 0;
|
|
5
|
+
let inflight = 0;
|
|
6
|
+
let lastActivity = now();
|
|
7
|
+
let sweeping = null;
|
|
8
|
+
let timer = null;
|
|
9
|
+
const tick = () => {
|
|
10
|
+
if (sweeping !== null || inflight > 0 || now() - lastActivity < timeoutMs) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const run = sweep().catch(onError).catch(noop);
|
|
14
|
+
sweeping = raceTimeout(run, { ms: waitMs, fallback: undefined }).finally(() => {
|
|
15
|
+
sweeping = null;
|
|
16
|
+
lastActivity = now();
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
const disarm = () => {
|
|
20
|
+
if (timer !== null) {
|
|
21
|
+
clearInterval(timer);
|
|
22
|
+
}
|
|
23
|
+
timer = null;
|
|
24
|
+
};
|
|
25
|
+
return {
|
|
26
|
+
configure(ms) {
|
|
27
|
+
timeoutMs = ms;
|
|
28
|
+
disarm();
|
|
29
|
+
if (ms <= 0) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
timer = setInterval(tick, Math.min(tickMs, ms));
|
|
33
|
+
if (typeof timer.unref === 'function') {
|
|
34
|
+
timer.unref();
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
async enter() {
|
|
38
|
+
inflight++;
|
|
39
|
+
lastActivity = now();
|
|
40
|
+
if (sweeping !== null) {
|
|
41
|
+
await sweeping;
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
exit() {
|
|
45
|
+
inflight--;
|
|
46
|
+
lastActivity = now();
|
|
47
|
+
},
|
|
48
|
+
close: disarm
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function noop() { }
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export
|
|
1
|
+
export interface KvCacheTypes {
|
|
2
2
|
k: string | undefined;
|
|
3
3
|
v: string | undefined;
|
|
4
|
-
}
|
|
4
|
+
}
|
|
5
|
+
export declare function adrenoSafeKvCache(device: 'cpu' | 'gpu' | undefined, { k, v }: KvCacheTypes, hostPlatform?: string): KvCacheTypes;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { platform } from 'os';
|
|
2
|
-
export function adrenoSafeKvCache(device,
|
|
3
|
-
if (device === 'cpu' || hostPlatform !== 'android')
|
|
4
|
-
return { k
|
|
2
|
+
export function adrenoSafeKvCache(device, { k, v }, hostPlatform = platform()) {
|
|
3
|
+
if (device === 'cpu' || hostPlatform !== 'android') {
|
|
4
|
+
return { k, v };
|
|
5
|
+
}
|
|
5
6
|
return { k: 'f16', v: 'f16' };
|
|
6
7
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export
|
|
1
|
+
export interface LlmGenerationParams {
|
|
2
2
|
temp?: number;
|
|
3
3
|
top_p?: number;
|
|
4
4
|
top_k?: number;
|
|
@@ -6,5 +6,5 @@ export type LlmGenerationParams = {
|
|
|
6
6
|
repeat_penalty?: number;
|
|
7
7
|
frequency_penalty?: number;
|
|
8
8
|
reasoning_budget: -1 | 0;
|
|
9
|
-
}
|
|
9
|
+
}
|
|
10
10
|
export declare function resolveLlmGenerationParams(modelName: string | undefined, reasoningEnabled: boolean | undefined, deviceDefault?: boolean): LlmGenerationParams | undefined;
|
|
@@ -31,11 +31,13 @@ export function resolveLlmGenerationParams(modelName, reasoningEnabled, deviceDe
|
|
|
31
31
|
const resolver = modelName
|
|
32
32
|
? PRESET_RESOLVERS.find((entry) => modelName.startsWith(entry.prefix))
|
|
33
33
|
: undefined;
|
|
34
|
-
if (resolver)
|
|
34
|
+
if (resolver) {
|
|
35
35
|
return resolver.resolve(reasoningEnabled);
|
|
36
|
+
}
|
|
36
37
|
const effective = reasoningEnabled ?? deviceDefault;
|
|
37
|
-
if (effective === undefined)
|
|
38
|
+
if (effective === undefined) {
|
|
38
39
|
return undefined;
|
|
40
|
+
}
|
|
39
41
|
return { reasoning_budget: effective ? -1 : 0 };
|
|
40
42
|
}
|
|
41
43
|
function qwen08BPreset(reasoningEnabled) {
|
|
@@ -14,7 +14,7 @@ export const QWEN_38_27B = 'Qwen3.8-27B-UD-Q4_K_XL';
|
|
|
14
14
|
export const MEDPSY_1_7B = 'medpsy-1.7b-q4_k_m-imat';
|
|
15
15
|
export const MEDPSY_4B = 'medpsy-4b-q4_k_m-imat';
|
|
16
16
|
export function isCapabilityProfile(value) {
|
|
17
|
-
return CAPABILITY_PROFILE_ORDER.
|
|
17
|
+
return CAPABILITY_PROFILE_ORDER.some((profile) => profile === value);
|
|
18
18
|
}
|
|
19
19
|
export function meetsMinCapabilityProfile(active, required) {
|
|
20
20
|
return CAPABILITY_PROFILE_ORDER.indexOf(active) >= CAPABILITY_PROFILE_ORDER.indexOf(required);
|
|
@@ -41,8 +41,9 @@ const PROFILE_TO_MODEL_NAME = new Map([
|
|
|
41
41
|
]);
|
|
42
42
|
export function capabilityProfileToModelName(profile) {
|
|
43
43
|
const name = PROFILE_TO_MODEL_NAME.get(profile);
|
|
44
|
-
if (!name)
|
|
44
|
+
if (!name) {
|
|
45
45
|
throw new Error(`no model for capability profile ${profile}`);
|
|
46
|
+
}
|
|
46
47
|
return name;
|
|
47
48
|
}
|
|
48
49
|
export const AGENT_MODEL_NAMES = [
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { ModelRegistryEntry, ToolDialect } from '@qvac/sdk';
|
|
2
|
+
import type { ImageModelSet } from '../tools/generate-image.ts';
|
|
3
|
+
import type { MusicModelStages } from '../tools/generate-music.ts';
|
|
2
4
|
import type { ModelAddon } from './model-source.ts';
|
|
3
5
|
export interface SdkModelAsset extends ModelRegistryEntry {
|
|
4
6
|
readonly src: string;
|
|
@@ -24,10 +26,11 @@ export interface CategoryDefault {
|
|
|
24
26
|
export declare const CATEGORY_DEFAULTS: ReadonlyArray<CategoryDefault>;
|
|
25
27
|
export declare function defaultVoiceModel(category: ModelCategory): string;
|
|
26
28
|
export declare function defaultTtsFor(profile: CapabilityProfile): CategoryDefault;
|
|
27
|
-
export
|
|
28
|
-
name: string;
|
|
29
|
-
addon: ModelAddon;
|
|
30
|
-
}
|
|
29
|
+
export interface CatalogModel {
|
|
30
|
+
readonly name: string;
|
|
31
|
+
readonly addon: ModelAddon;
|
|
32
|
+
}
|
|
33
|
+
export declare function infraModelsFor(profile: CapabilityProfile): CatalogModel[];
|
|
31
34
|
export declare function mediaModelNameFor(category: ModelCategory, profile: CapabilityProfile): string;
|
|
32
35
|
export interface DiffusionCatalogEntry {
|
|
33
36
|
readonly choice: ImageModelChoice;
|
|
@@ -62,12 +65,7 @@ export declare const AUDIOGEN_CATALOG: ReadonlyArray<AudioGenCatalogEntry>;
|
|
|
62
65
|
export declare function musicDefaultSteps(choice: string | undefined): number | undefined;
|
|
63
66
|
export declare function musicChoiceForDit(dit: string): MusicModelChoice | undefined;
|
|
64
67
|
export declare function musicSizeBytes(entry: AudioGenCatalogEntry): number;
|
|
65
|
-
export declare function musicModelSet(choice: string | undefined):
|
|
66
|
-
dit: string;
|
|
67
|
-
textEnc: string;
|
|
68
|
-
lm: string;
|
|
69
|
-
vae: string;
|
|
70
|
-
} | null;
|
|
68
|
+
export declare function musicModelSet(choice: string | undefined): MusicModelStages | null;
|
|
71
69
|
export interface AudioGenDownloadMetadata {
|
|
72
70
|
readonly companions: ReadonlyArray<string>;
|
|
73
71
|
readonly assetSizes: Readonly<Record<string, number>>;
|
|
@@ -80,17 +78,9 @@ export interface AgentSkillModelInput {
|
|
|
80
78
|
readonly imageModelChoice?: ImageModelChoice | null;
|
|
81
79
|
readonly musicModelChoice?: MusicModelChoice | null;
|
|
82
80
|
}
|
|
83
|
-
export declare function skillModelsForAgent(agent: AgentSkillModelInput): ReadonlyArray<
|
|
84
|
-
readonly name: string;
|
|
85
|
-
readonly addon: ModelAddon;
|
|
86
|
-
}>;
|
|
81
|
+
export declare function skillModelsForAgent(agent: AgentSkillModelInput): ReadonlyArray<CatalogModel>;
|
|
87
82
|
export declare function diffusionSizeBytes(entry: DiffusionCatalogEntry): number;
|
|
88
|
-
export declare function imageModelFor(choice: string | undefined):
|
|
89
|
-
model: string;
|
|
90
|
-
llmModel?: string | undefined;
|
|
91
|
-
vaeModel?: string | undefined;
|
|
92
|
-
prediction?: 'flux2_flow' | undefined;
|
|
93
|
-
} | null;
|
|
83
|
+
export declare function imageModelFor(choice: string | undefined): ImageModelSet | null;
|
|
94
84
|
export interface ImageClamps {
|
|
95
85
|
maxDim?: number;
|
|
96
86
|
maxSteps?: number;
|
|
@@ -105,13 +95,21 @@ export interface CuratedListable {
|
|
|
105
95
|
}
|
|
106
96
|
export declare function curatedListables(): CuratedListable[];
|
|
107
97
|
export declare function curatedModelAsset(name: string, addon: ModelRegistryEntry['addon']): SdkModelAsset | undefined;
|
|
98
|
+
export declare const CUSTOM_TASK_TYPES: readonly ['llm'];
|
|
99
|
+
export type CustomTaskType = (typeof CUSTOM_TASK_TYPES)[number];
|
|
108
100
|
export interface CustomModelEntry {
|
|
109
101
|
readonly name: string;
|
|
110
102
|
readonly src: string;
|
|
111
103
|
readonly projectionSrc?: string;
|
|
104
|
+
readonly taskType?: CustomTaskType;
|
|
105
|
+
readonly expectedSize?: number;
|
|
106
|
+
readonly label?: string;
|
|
107
|
+
readonly contextLength?: number;
|
|
112
108
|
}
|
|
113
109
|
export declare function setCustomModels(entries: ReadonlyArray<CustomModelEntry>): void;
|
|
114
|
-
export declare function
|
|
110
|
+
export declare function customModels(): ReadonlyArray<CustomModelEntry>;
|
|
111
|
+
export declare function customContextLength(name: string): number | undefined;
|
|
112
|
+
export declare function customModelSrc(name: string, addon: ModelRegistryEntry['addon']): string | undefined;
|
|
115
113
|
export declare function customToolDialect(name: string): ToolDialect | undefined;
|
|
116
114
|
export declare function customProjectionMap(): Record<string, string>;
|
|
117
115
|
export declare function companionRegistryPaths(): Map<string, string[]>;
|
|
@@ -56,8 +56,9 @@ export const LLM_CATALOG = [
|
|
|
56
56
|
export function defaultProjectionMap() {
|
|
57
57
|
const map = {};
|
|
58
58
|
for (const entry of LLM_CATALOG) {
|
|
59
|
-
if (entry.projection)
|
|
59
|
+
if (entry.projection) {
|
|
60
60
|
map[entry.name] = entry.projection.src;
|
|
61
|
+
}
|
|
61
62
|
}
|
|
62
63
|
return map;
|
|
63
64
|
}
|
|
@@ -73,13 +74,18 @@ export const CATEGORY_DEFAULTS = [
|
|
|
73
74
|
];
|
|
74
75
|
export function defaultVoiceModel(category) {
|
|
75
76
|
const entry = CATEGORY_DEFAULTS.find((candidate) => candidate.category === category);
|
|
76
|
-
if (!entry)
|
|
77
|
+
if (!entry) {
|
|
77
78
|
throw new Error(`no default model for category ${category}`);
|
|
79
|
+
}
|
|
78
80
|
return entry.asset.src;
|
|
79
81
|
}
|
|
80
82
|
export function defaultTtsFor(profile) {
|
|
81
83
|
const name = defaultTtsModelName(profile);
|
|
82
|
-
|
|
84
|
+
const entry = CATEGORY_DEFAULTS.find((candidate) => candidate.name === name);
|
|
85
|
+
if (!entry) {
|
|
86
|
+
throw new Error(`no default tts model named ${name}`);
|
|
87
|
+
}
|
|
88
|
+
return entry;
|
|
83
89
|
}
|
|
84
90
|
export function infraModelsFor(profile) {
|
|
85
91
|
const tts = defaultTtsFor(profile);
|
|
@@ -87,11 +93,13 @@ export function infraModelsFor(profile) {
|
|
|
87
93
|
return [tts, ...rest].map((entry) => ({ name: entry.name, addon: entry.asset.addon }));
|
|
88
94
|
}
|
|
89
95
|
export function mediaModelNameFor(category, profile) {
|
|
90
|
-
if (category === 'tts')
|
|
96
|
+
if (category === 'tts') {
|
|
91
97
|
return defaultTtsFor(profile).name;
|
|
98
|
+
}
|
|
92
99
|
const entry = CATEGORY_DEFAULTS.find((candidate) => candidate.category === category);
|
|
93
|
-
if (!entry)
|
|
100
|
+
if (!entry) {
|
|
94
101
|
throw new Error(`no default model for category ${category}`);
|
|
102
|
+
}
|
|
95
103
|
return entry.name;
|
|
96
104
|
}
|
|
97
105
|
const IMAGE_GENERATION_SKILL = 'image-generation';
|
|
@@ -123,10 +131,12 @@ export const DIFFUSION_CATALOG = [
|
|
|
123
131
|
];
|
|
124
132
|
function diffusionAssets(entry) {
|
|
125
133
|
const assets = [entry.model];
|
|
126
|
-
if (entry.llmModel)
|
|
134
|
+
if (entry.llmModel) {
|
|
127
135
|
assets.push(entry.llmModel);
|
|
128
|
-
|
|
136
|
+
}
|
|
137
|
+
if (entry.vaeModel) {
|
|
129
138
|
assets.push(entry.vaeModel);
|
|
139
|
+
}
|
|
130
140
|
return assets;
|
|
131
141
|
}
|
|
132
142
|
function diffusionCatalogEntry(model) {
|
|
@@ -142,12 +152,14 @@ export function diffusionDownloadMetadata(model, addon) {
|
|
|
142
152
|
if (addon !== 'diffusion')
|
|
143
153
|
return undefined;
|
|
144
154
|
const entry = diffusionCatalogEntry(model);
|
|
145
|
-
if (!entry)
|
|
155
|
+
if (!entry) {
|
|
146
156
|
return undefined;
|
|
157
|
+
}
|
|
147
158
|
const assets = diffusionAssets(entry);
|
|
148
159
|
const assetSizes = {};
|
|
149
|
-
for (const asset of assets)
|
|
160
|
+
for (const asset of assets) {
|
|
150
161
|
assetSizes[asset.src] = asset.expectedSize;
|
|
162
|
+
}
|
|
151
163
|
return {
|
|
152
164
|
companions: assets.slice(1).map((asset) => asset.src),
|
|
153
165
|
assetSizes
|
|
@@ -202,8 +214,9 @@ export function musicSizeBytes(entry) {
|
|
|
202
214
|
}
|
|
203
215
|
export function musicModelSet(choice) {
|
|
204
216
|
const entry = AUDIOGEN_CATALOG.find((candidate) => candidate.choice === choice);
|
|
205
|
-
if (!entry)
|
|
217
|
+
if (!entry) {
|
|
206
218
|
return null;
|
|
219
|
+
}
|
|
207
220
|
return {
|
|
208
221
|
dit: entry.dit.src,
|
|
209
222
|
textEnc: entry.textEnc.src,
|
|
@@ -215,12 +228,14 @@ export function audioGenDownloadMetadata(model, addon) {
|
|
|
215
228
|
if (addon !== 'audiogen')
|
|
216
229
|
return undefined;
|
|
217
230
|
const entry = AUDIOGEN_CATALOG.find((candidate) => candidate.name === model || candidate.dit.name === model || candidate.dit.src === model);
|
|
218
|
-
if (!entry)
|
|
231
|
+
if (!entry) {
|
|
219
232
|
return undefined;
|
|
233
|
+
}
|
|
220
234
|
const stages = audioGenStages(entry);
|
|
221
235
|
const assetSizes = {};
|
|
222
|
-
for (const asset of stages)
|
|
236
|
+
for (const asset of stages) {
|
|
223
237
|
assetSizes[asset.src] = asset.expectedSize;
|
|
238
|
+
}
|
|
224
239
|
return {
|
|
225
240
|
companions: stages.slice(1).map((asset) => asset.src),
|
|
226
241
|
assetSizes
|
|
@@ -235,14 +250,16 @@ export function skillModelsForAgent(agent) {
|
|
|
235
250
|
if (agentHasSkill(agent, IMAGE_GENERATION_SKILL)) {
|
|
236
251
|
const choice = agent.imageModelChoice ?? DEFAULT_IMAGE_MODEL_CHOICE;
|
|
237
252
|
const entry = DIFFUSION_CATALOG.find((candidate) => candidate.choice === choice);
|
|
238
|
-
if (entry)
|
|
253
|
+
if (entry) {
|
|
239
254
|
models.push({ name: entry.name, addon: entry.model.addon });
|
|
255
|
+
}
|
|
240
256
|
}
|
|
241
257
|
if (agentHasSkill(agent, MUSIC_GENERATION_SKILL)) {
|
|
242
258
|
const choice = agent.musicModelChoice ?? DEFAULT_MUSIC_MODEL_CHOICE;
|
|
243
259
|
const entry = AUDIOGEN_CATALOG.find((candidate) => candidate.choice === choice);
|
|
244
|
-
if (entry)
|
|
260
|
+
if (entry) {
|
|
245
261
|
models.push({ name: entry.name, addon: entry.dit.addon });
|
|
262
|
+
}
|
|
246
263
|
}
|
|
247
264
|
return models;
|
|
248
265
|
}
|
|
@@ -251,13 +268,14 @@ export function diffusionSizeBytes(entry) {
|
|
|
251
268
|
}
|
|
252
269
|
export function imageModelFor(choice) {
|
|
253
270
|
const entry = DIFFUSION_CATALOG.find((candidate) => candidate.choice === choice);
|
|
254
|
-
if (!entry)
|
|
271
|
+
if (!entry) {
|
|
255
272
|
return null;
|
|
273
|
+
}
|
|
256
274
|
return {
|
|
257
275
|
model: entry.model.src,
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
276
|
+
llmModel: entry.llmModel?.src,
|
|
277
|
+
vaeModel: entry.vaeModel?.src,
|
|
278
|
+
prediction: entry.prediction
|
|
261
279
|
};
|
|
262
280
|
}
|
|
263
281
|
export function imageClampsFromEnv(env) {
|
|
@@ -267,9 +285,10 @@ export function imageClampsFromEnv(env) {
|
|
|
267
285
|
};
|
|
268
286
|
const maxDim = positive(env.QVAC_IMAGE_MAX_DIM);
|
|
269
287
|
const maxSteps = positive(env.QVAC_IMAGE_MAX_STEPS);
|
|
270
|
-
if (!maxDim && !maxSteps)
|
|
288
|
+
if (!maxDim && !maxSteps) {
|
|
271
289
|
return undefined;
|
|
272
|
-
|
|
290
|
+
}
|
|
291
|
+
return { maxDim, maxSteps };
|
|
273
292
|
}
|
|
274
293
|
export function imageModelFromEnv(env, onIgnoredCompanions, onIgnoredPrediction) {
|
|
275
294
|
const catalog = imageModelFor(env.QVAC_IMAGE_MODEL);
|
|
@@ -279,12 +298,14 @@ export function imageModelFromEnv(env, onIgnoredCompanions, onIgnoredPrediction)
|
|
|
279
298
|
}
|
|
280
299
|
return catalog;
|
|
281
300
|
}
|
|
282
|
-
if (!env.QVAC_IMAGE_MODEL)
|
|
301
|
+
if (!env.QVAC_IMAGE_MODEL) {
|
|
283
302
|
return undefined;
|
|
303
|
+
}
|
|
284
304
|
const prediction = env.QVAC_IMAGE_PREDICTION || undefined;
|
|
285
305
|
const fluxSet = Boolean(env.QVAC_IMAGE_LLM && env.QVAC_IMAGE_VAE);
|
|
286
|
-
if (prediction && !fluxSet)
|
|
306
|
+
if (prediction && !fluxSet) {
|
|
287
307
|
onIgnoredPrediction?.();
|
|
308
|
+
}
|
|
288
309
|
return {
|
|
289
310
|
model: env.QVAC_IMAGE_MODEL,
|
|
290
311
|
llmModel: env.QVAC_IMAGE_LLM || undefined,
|
|
@@ -304,44 +325,55 @@ export function curatedListables() {
|
|
|
304
325
|
...DIFFUSION_CATALOG.map((entry) => ({
|
|
305
326
|
name: entry.name,
|
|
306
327
|
asset: entry.model,
|
|
307
|
-
companions: [entry.llmModel, entry.vaeModel].filter(
|
|
328
|
+
companions: [entry.llmModel, entry.vaeModel].filter((asset) => asset !== undefined)
|
|
308
329
|
}))
|
|
309
330
|
];
|
|
310
331
|
}
|
|
311
332
|
export function curatedModelAsset(name, addon) {
|
|
312
333
|
return curatedListables().find((entry) => entry.asset.addon === addon && (entry.name === name || entry.asset.name === name))?.asset;
|
|
313
334
|
}
|
|
335
|
+
export const CUSTOM_TASK_TYPES = ['llm'];
|
|
314
336
|
let CUSTOM_MODELS = new Map();
|
|
315
337
|
export function setCustomModels(entries) {
|
|
316
338
|
CUSTOM_MODELS = new Map(entries.map((entry) => [entry.name, entry]));
|
|
317
339
|
}
|
|
318
|
-
export function
|
|
319
|
-
return CUSTOM_MODELS.
|
|
340
|
+
export function customModels() {
|
|
341
|
+
return [...CUSTOM_MODELS.values()];
|
|
342
|
+
}
|
|
343
|
+
export function customContextLength(name) {
|
|
344
|
+
return CUSTOM_MODELS.get(name)?.contextLength;
|
|
345
|
+
}
|
|
346
|
+
export function customModelSrc(name, addon) {
|
|
347
|
+
const entry = CUSTOM_MODELS.get(name);
|
|
348
|
+
return entry && (entry.taskType ?? 'llm') === addon ? entry.src : undefined;
|
|
320
349
|
}
|
|
321
350
|
export function customToolDialect(name) {
|
|
322
351
|
const entry = CUSTOM_MODELS.get(name);
|
|
323
|
-
return entry
|
|
352
|
+
return entry
|
|
353
|
+
? detectToolDialect(entry.src, entry.label?.replace(/\s+/g, '-') ?? entry.name)
|
|
354
|
+
: undefined;
|
|
324
355
|
}
|
|
325
356
|
export function customProjectionMap() {
|
|
326
357
|
const map = {};
|
|
327
358
|
for (const entry of CUSTOM_MODELS.values()) {
|
|
328
|
-
if (entry.projectionSrc)
|
|
359
|
+
if (entry.projectionSrc) {
|
|
329
360
|
map[entry.name] = entry.projectionSrc;
|
|
361
|
+
}
|
|
330
362
|
}
|
|
331
363
|
return map;
|
|
332
364
|
}
|
|
333
365
|
export function companionRegistryPaths() {
|
|
334
366
|
const map = new Map();
|
|
335
367
|
for (const entry of LLM_CATALOG) {
|
|
336
|
-
if (entry.projection)
|
|
368
|
+
if (entry.projection) {
|
|
337
369
|
map.set(entry.weight.registryPath, [entry.projection.registryPath]);
|
|
370
|
+
}
|
|
338
371
|
}
|
|
339
372
|
for (const entry of DIFFUSION_CATALOG) {
|
|
340
|
-
const companions = [entry.llmModel, entry.vaeModel]
|
|
341
|
-
|
|
342
|
-
.map((asset) => asset.registryPath);
|
|
343
|
-
if (companions.length)
|
|
373
|
+
const companions = [entry.llmModel, entry.vaeModel].flatMap((asset) => asset ? [asset.registryPath] : []);
|
|
374
|
+
if (companions.length) {
|
|
344
375
|
map.set(entry.model.registryPath, companions);
|
|
376
|
+
}
|
|
345
377
|
}
|
|
346
378
|
for (const entry of AUDIOGEN_CATALOG) {
|
|
347
379
|
map.set(entry.dit.registryPath, [
|
|
@@ -355,8 +387,9 @@ export function companionRegistryPaths() {
|
|
|
355
387
|
export function audioGenModelByName(name) {
|
|
356
388
|
for (const entry of AUDIOGEN_CATALOG) {
|
|
357
389
|
for (const stage of [entry.dit, entry.textEnc, entry.lm, entry.vae]) {
|
|
358
|
-
if (stage.name === name || entry.name === name)
|
|
390
|
+
if (stage.name === name || entry.name === name) {
|
|
359
391
|
return name === entry.name ? entry.dit : stage;
|
|
392
|
+
}
|
|
360
393
|
}
|
|
361
394
|
}
|
|
362
395
|
return undefined;
|
|
@@ -15,4 +15,7 @@ export interface DeleteModelSummary {
|
|
|
15
15
|
readonly freedBytes: number;
|
|
16
16
|
}
|
|
17
17
|
export declare function summarizeDelete(result: DeleteModelResult): DeleteModelSummary;
|
|
18
|
-
export
|
|
18
|
+
export interface DeleteModelOptions {
|
|
19
|
+
readonly modelsDir?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function deleteModelFiles(sdk: ModelDeleteSdk, name: string, { modelsDir }?: DeleteModelOptions): Promise<DeleteModelResult>;
|
|
@@ -1,27 +1,40 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
|
-
import {
|
|
2
|
+
import { customDownloads } from './custom-model-cache.js';
|
|
3
|
+
import { curatedListables, customModels, musicListables } from './model-catalog.js';
|
|
3
4
|
export function summarizeDelete(result) {
|
|
4
5
|
return { name: result.name, removed: result.removed.length, freedBytes: result.freedBytes };
|
|
5
6
|
}
|
|
6
|
-
export async function deleteModelFiles(sdk, name) {
|
|
7
|
-
const
|
|
7
|
+
export async function deleteModelFiles(sdk, name, { modelsDir } = {}) {
|
|
8
|
+
const custom = customModels().find((entry) => entry.name === name);
|
|
9
|
+
const { files, dirs } = custom
|
|
10
|
+
? await customDownloads(custom, modelsDir)
|
|
11
|
+
: { files: await catalogFiles(sdk, name), dirs: [] };
|
|
8
12
|
const removed = [];
|
|
13
|
+
for (const filePath of new Set(files)) {
|
|
14
|
+
const bytes = await onDiskSize(filePath);
|
|
15
|
+
if (bytes === null) {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
await fs.promises.rm(filePath, { force: true });
|
|
19
|
+
removed.push({ path: filePath, bytes });
|
|
20
|
+
}
|
|
21
|
+
for (const dir of dirs) {
|
|
22
|
+
await fs.promises.rm(dir, { recursive: true, force: true });
|
|
23
|
+
}
|
|
24
|
+
return { name, removed, freedBytes: removed.reduce((sum, file) => sum + file.bytes, 0) };
|
|
25
|
+
}
|
|
26
|
+
async function catalogFiles(sdk, name) {
|
|
27
|
+
const paths = [];
|
|
9
28
|
for (const catalogName of namesToPurge(name)) {
|
|
10
29
|
const info = await sdk.getModelInfo({ name: catalogName }).catch(() => null);
|
|
11
|
-
if (!info)
|
|
30
|
+
if (!info) {
|
|
12
31
|
continue;
|
|
32
|
+
}
|
|
13
33
|
for (const file of info.cacheFiles) {
|
|
14
|
-
|
|
15
|
-
continue;
|
|
16
|
-
seen.add(file.path);
|
|
17
|
-
const bytes = await onDiskSize(file.path);
|
|
18
|
-
if (bytes === null)
|
|
19
|
-
continue;
|
|
20
|
-
await fs.promises.rm(file.path, { force: true });
|
|
21
|
-
removed.push({ path: file.path, bytes });
|
|
34
|
+
paths.push(file.path);
|
|
22
35
|
}
|
|
23
36
|
}
|
|
24
|
-
return
|
|
37
|
+
return paths;
|
|
25
38
|
}
|
|
26
39
|
async function onDiskSize(filePath) {
|
|
27
40
|
try {
|
|
@@ -36,12 +49,14 @@ function namesToPurge(name) {
|
|
|
36
49
|
const curated = curatedListables().find((entry) => entry.name === name || entry.asset.name === name);
|
|
37
50
|
if (curated) {
|
|
38
51
|
const names = [curated.asset.name, ...curated.companions.map((companion) => companion.name)];
|
|
39
|
-
if (curated.projection)
|
|
52
|
+
if (curated.projection) {
|
|
40
53
|
names.push(curated.projection.name);
|
|
54
|
+
}
|
|
41
55
|
return names;
|
|
42
56
|
}
|
|
43
57
|
const music = musicListables().find((entry) => entry.name === name || entry.asset.name === name);
|
|
44
|
-
if (music)
|
|
58
|
+
if (music) {
|
|
45
59
|
return [music.asset.name, ...music.companions.map((stage) => stage.name)];
|
|
60
|
+
}
|
|
46
61
|
return [name];
|
|
47
62
|
}
|
|
@@ -18,6 +18,7 @@ export interface ModelInfo {
|
|
|
18
18
|
supportsImages: boolean;
|
|
19
19
|
expectedSize: number;
|
|
20
20
|
actualSize?: number;
|
|
21
|
+
label?: string;
|
|
21
22
|
}
|
|
22
23
|
export interface ListModelsOptions {
|
|
23
24
|
type?: ModelType;
|
|
@@ -31,12 +32,22 @@ interface ModelStatus {
|
|
|
31
32
|
expectedSize?: number;
|
|
32
33
|
actualSize?: number;
|
|
33
34
|
}
|
|
34
|
-
export
|
|
35
|
+
export interface ModelStatusCache {
|
|
35
36
|
readonly entries: Map<string, ModelStatus>;
|
|
36
37
|
epoch: number;
|
|
37
|
-
}
|
|
38
|
+
}
|
|
38
39
|
export declare const MODEL_STATUS_TTL_MS = 30000;
|
|
39
40
|
export declare function createModelStatusCache(): ModelStatusCache;
|
|
40
41
|
export declare function invalidateModelStatusCache(cache: ModelStatusCache): void;
|
|
41
|
-
export
|
|
42
|
+
export interface ListModelsRuntime {
|
|
43
|
+
cache?: ModelStatusCache | undefined;
|
|
44
|
+
projectionFor?: ((name: string) => string | undefined) | undefined;
|
|
45
|
+
}
|
|
46
|
+
export declare function listModels(sdk: ModelListSdk, { type, cachedOnly, fullRegistry }?: ListModelsOptions, { cache, projectionFor }?: ListModelsRuntime): Promise<ModelInfo[]>;
|
|
47
|
+
export interface CustomModelRowsContext {
|
|
48
|
+
readonly modelsDir?: string;
|
|
49
|
+
readonly loaded: ReadonlySet<string>;
|
|
50
|
+
}
|
|
51
|
+
export declare function customModelRows({ type, cachedOnly }: ListModelsOptions, { modelsDir, loaded }: CustomModelRowsContext): Promise<ModelInfo[]>;
|
|
52
|
+
export declare function mergeCustomRows(catalog: ReadonlyArray<ModelInfo>, custom: ReadonlyArray<ModelInfo>): ModelInfo[];
|
|
42
53
|
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isCustomModelCached } from './custom-model-cache.js';
|
|
2
|
+
import { companionRegistryPaths, curatedListables, customModels, musicListables } from './model-catalog.js';
|
|
2
3
|
export const MODEL_STATUS_TTL_MS = 30_000;
|
|
3
4
|
export function createModelStatusCache() {
|
|
4
5
|
return { entries: new Map(), epoch: 0 };
|
|
@@ -14,8 +15,9 @@ async function mapPool(items, limit, fn) {
|
|
|
14
15
|
const worker = async () => {
|
|
15
16
|
while (true) {
|
|
16
17
|
const i = cursor++;
|
|
17
|
-
if (i >= items.length)
|
|
18
|
+
if (i >= items.length) {
|
|
18
19
|
return;
|
|
20
|
+
}
|
|
19
21
|
results[i] = await fn(items[i]);
|
|
20
22
|
}
|
|
21
23
|
};
|
|
@@ -45,13 +47,14 @@ async function musicRows(hydrate) {
|
|
|
45
47
|
}
|
|
46
48
|
return rows;
|
|
47
49
|
}
|
|
48
|
-
export async function listModels(sdk, { type, cachedOnly, fullRegistry } = {}, cache, projectionFor) {
|
|
50
|
+
export async function listModels(sdk, { type, cachedOnly, fullRegistry } = {}, { cache, projectionFor } = {}) {
|
|
49
51
|
const now = Date.now();
|
|
50
52
|
const seesImages = (name, addon) => addon === 'llm' && Boolean(projectionFor?.(name));
|
|
51
53
|
const hydrate = async (registryPath, catalogName) => {
|
|
52
54
|
const hit = cache?.entries.get(registryPath);
|
|
53
|
-
if (hit && now - hit.at < MODEL_STATUS_TTL_MS)
|
|
55
|
+
if (hit && now - hit.at < MODEL_STATUS_TTL_MS) {
|
|
54
56
|
return hit;
|
|
57
|
+
}
|
|
55
58
|
const epoch = cache?.epoch;
|
|
56
59
|
const info = catalogName
|
|
57
60
|
? await sdk.getModelInfo({ name: catalogName }).catch(() => null)
|
|
@@ -63,8 +66,9 @@ export async function listModels(sdk, { type, cachedOnly, fullRegistry } = {}, c
|
|
|
63
66
|
expectedSize: info?.expectedSize,
|
|
64
67
|
actualSize: info?.actualSize
|
|
65
68
|
};
|
|
66
|
-
if (cache && cache.epoch === epoch)
|
|
69
|
+
if (cache && cache.epoch === epoch) {
|
|
67
70
|
cache.entries.set(registryPath, status);
|
|
71
|
+
}
|
|
68
72
|
return status;
|
|
69
73
|
};
|
|
70
74
|
if (!fullRegistry) {
|
|
@@ -98,8 +102,9 @@ export async function listModels(sdk, { type, cachedOnly, fullRegistry } = {}, c
|
|
|
98
102
|
}
|
|
99
103
|
const entries = await sdk.modelRegistrySearch(type ? { addon: type } : {});
|
|
100
104
|
const catalog = new Map();
|
|
101
|
-
for (const c of sdk.models)
|
|
105
|
+
for (const c of sdk.models) {
|
|
102
106
|
catalog.set(c.registryPath, c.name);
|
|
107
|
+
}
|
|
103
108
|
const rows = await mapPool(entries, STATUS_CONCURRENCY, async (entry) => {
|
|
104
109
|
const status = await hydrate(entry.registryPath, catalog.get(entry.registryPath));
|
|
105
110
|
const companions = COMPANIONS_BY_WEIGHT.get(entry.registryPath) ?? [];
|
|
@@ -121,3 +126,25 @@ export async function listModels(sdk, { type, cachedOnly, fullRegistry } = {}, c
|
|
|
121
126
|
});
|
|
122
127
|
return cachedOnly ? rows.filter((row) => row.isCached) : rows;
|
|
123
128
|
}
|
|
129
|
+
export async function customModelRows({ type, cachedOnly }, { modelsDir, loaded }) {
|
|
130
|
+
const entries = customModels().filter((entry) => !type || (entry.taskType ?? 'llm') === type);
|
|
131
|
+
const rows = await Promise.all(entries.map(async (entry) => {
|
|
132
|
+
const addon = entry.taskType ?? 'llm';
|
|
133
|
+
return {
|
|
134
|
+
name: entry.name,
|
|
135
|
+
type: addon,
|
|
136
|
+
registryPath: entry.src,
|
|
137
|
+
registrySource: 'custom',
|
|
138
|
+
isCached: await isCustomModelCached(entry, modelsDir),
|
|
139
|
+
isLoaded: loaded.has(entry.name),
|
|
140
|
+
supportsImages: addon === 'llm' && Boolean(entry.projectionSrc),
|
|
141
|
+
expectedSize: entry.expectedSize ?? 0,
|
|
142
|
+
label: entry.label
|
|
143
|
+
};
|
|
144
|
+
}));
|
|
145
|
+
return cachedOnly ? rows.filter((row) => row.isCached) : rows;
|
|
146
|
+
}
|
|
147
|
+
export function mergeCustomRows(catalog, custom) {
|
|
148
|
+
const shadowed = new Set(custom.map((row) => row.name));
|
|
149
|
+
return [...catalog.filter((row) => !shadowed.has(row.name)), ...custom];
|
|
150
|
+
}
|