@qvac/harness 0.4.0 → 0.6.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 +740 -141
- package/README.md +75 -7
- package/dist/harness.bundle +72 -50
- package/dist-lib/index.d.ts +49 -39
- package/dist-lib/index.js +448 -161
- 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 +193 -132
- 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 +9 -7
- package/dist-lib/lib/capabilities/preview-model-source.js +80 -28
- 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 +13 -32
- package/dist-lib/lib/connect.js +170 -112
- package/dist-lib/lib/context-window.js +25 -21
- package/dist-lib/lib/contract-types.d.ts +35 -15
- 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 +10 -1
- package/dist-lib/lib/models/custom-model-cache.js +43 -15
- package/dist-lib/lib/models/gguf-header.d.ts +3 -2
- package/dist-lib/lib/models/gguf-header.js +44 -22
- 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 +15 -20
- package/dist-lib/lib/models/model-catalog.js +66 -31
- package/dist-lib/lib/models/model-delete.js +18 -8
- package/dist-lib/lib/models/model-handle.js +2 -1
- package/dist-lib/lib/models/model-list.d.ts +8 -3
- package/dist-lib/lib/models/model-list.js +11 -6
- package/dist-lib/lib/models/model-pool.d.ts +48 -10
- package/dist-lib/lib/models/model-pool.js +106 -45
- package/dist-lib/lib/models/model-source.js +10 -5
- 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 +122 -66
- 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 +39 -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 +9 -0
- package/dist-lib/spec/calls.js +3 -0
- package/dist-lib/spec/hrpc/hrpc.json +39 -0
- package/dist-lib/spec/hrpc/index.js +39 -3
- package/dist-lib/spec/hrpc/messages.js +105 -8
- package/dist-lib/spec/hyperschema/index.js +105 -8
- package/dist-lib/spec/hyperschema/schema.json +77 -1
- package/dist-lib/spec/hyperschema/types.d.ts +25 -1
- package/package.json +14 -14
- package/worker/harness-sidecar.mjs +15 -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
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsonrepair } from 'jsonrepair';
|
|
2
|
+
import { isRecord } from '../../guards.js';
|
|
2
3
|
import { hlog } from '../../log.js';
|
|
3
4
|
const STRUCTURED_TYPES = new Set(['object', 'array']);
|
|
4
5
|
export class ArgRepairHook {
|
|
@@ -9,11 +10,13 @@ export class ArgRepairHook {
|
|
|
9
10
|
let args = ctx.args;
|
|
10
11
|
for (const [key, schema] of Object.entries(ctx.parameters.properties)) {
|
|
11
12
|
const value = args[key];
|
|
12
|
-
if (typeof value !== 'string')
|
|
13
|
+
if (typeof value !== 'string') {
|
|
13
14
|
continue;
|
|
15
|
+
}
|
|
14
16
|
const types = structuredTypes(schema);
|
|
15
|
-
if (types.size === 0)
|
|
17
|
+
if (types.size === 0) {
|
|
16
18
|
continue;
|
|
19
|
+
}
|
|
17
20
|
const parsed = parseStructured(value, types);
|
|
18
21
|
if (parsed === null) {
|
|
19
22
|
hlog('arg repair declined', { tool: ctx.toolName, param: key, length: value.length });
|
|
@@ -21,8 +24,9 @@ export class ArgRepairHook {
|
|
|
21
24
|
}
|
|
22
25
|
args = { ...args, [key]: parsed };
|
|
23
26
|
}
|
|
24
|
-
if (args !== ctx.args)
|
|
27
|
+
if (args !== ctx.args) {
|
|
25
28
|
return { args };
|
|
29
|
+
}
|
|
26
30
|
}
|
|
27
31
|
}
|
|
28
32
|
function parseStructured(value, types) {
|
|
@@ -36,16 +40,18 @@ function parseStructured(value, types) {
|
|
|
36
40
|
return null;
|
|
37
41
|
}
|
|
38
42
|
const accepted = accept(parsed, types);
|
|
39
|
-
if (accepted !== null)
|
|
43
|
+
if (accepted !== null) {
|
|
40
44
|
return accepted;
|
|
45
|
+
}
|
|
41
46
|
if (Array.isArray(parsed) &&
|
|
42
47
|
types.has('object') &&
|
|
43
|
-
|
|
48
|
+
isPlainObject(parsed[0]) &&
|
|
44
49
|
typeof parsed.at(-1) === 'string') {
|
|
45
50
|
return parsed[0];
|
|
46
51
|
}
|
|
47
|
-
if (text[0] === '"' && types.has('object'))
|
|
52
|
+
if (text[0] === '"' && types.has('object')) {
|
|
48
53
|
return accept(read(`{${text}}`), types);
|
|
54
|
+
}
|
|
49
55
|
return null;
|
|
50
56
|
}
|
|
51
57
|
function read(text) {
|
|
@@ -57,7 +63,7 @@ function read(text) {
|
|
|
57
63
|
}
|
|
58
64
|
}
|
|
59
65
|
function accept(value, types) {
|
|
60
|
-
if (
|
|
66
|
+
if (isPlainObject(value) && types.has('object'))
|
|
61
67
|
return value;
|
|
62
68
|
if (Array.isArray(value) && types.has('array'))
|
|
63
69
|
return value;
|
|
@@ -65,24 +71,28 @@ function accept(value, types) {
|
|
|
65
71
|
}
|
|
66
72
|
function structuredTypes(schema) {
|
|
67
73
|
const found = new Set();
|
|
68
|
-
if (!
|
|
74
|
+
if (!isPlainObject(schema)) {
|
|
69
75
|
return found;
|
|
76
|
+
}
|
|
70
77
|
const declared = Array.isArray(schema.type) ? schema.type : [schema.type];
|
|
71
78
|
for (const type of declared) {
|
|
72
|
-
if (typeof type === 'string' && STRUCTURED_TYPES.has(type))
|
|
79
|
+
if (typeof type === 'string' && STRUCTURED_TYPES.has(type)) {
|
|
73
80
|
found.add(type);
|
|
81
|
+
}
|
|
74
82
|
}
|
|
75
83
|
for (const key of ['oneOf', 'anyOf']) {
|
|
76
84
|
const branches = schema[key];
|
|
77
|
-
if (!Array.isArray(branches))
|
|
85
|
+
if (!Array.isArray(branches)) {
|
|
78
86
|
continue;
|
|
87
|
+
}
|
|
79
88
|
for (const branch of branches) {
|
|
80
|
-
for (const type of structuredTypes(branch))
|
|
89
|
+
for (const type of structuredTypes(branch)) {
|
|
81
90
|
found.add(type);
|
|
91
|
+
}
|
|
82
92
|
}
|
|
83
93
|
}
|
|
84
94
|
return found;
|
|
85
95
|
}
|
|
86
|
-
function
|
|
87
|
-
return
|
|
96
|
+
function isPlainObject(value) {
|
|
97
|
+
return isRecord(value) && !Array.isArray(value);
|
|
88
98
|
}
|
|
@@ -11,8 +11,9 @@ export class SkillCatalogGuardHook {
|
|
|
11
11
|
const known = new Set(entries.map((entry) => (typeof entry === 'string' ? entry : entry.name)));
|
|
12
12
|
const raw = ctx.args.name ?? ctx.args.skill_name ?? ctx.args.skill;
|
|
13
13
|
const name = typeof raw === 'string' ? raw : '';
|
|
14
|
-
if (known.has(name))
|
|
14
|
+
if (known.has(name)) {
|
|
15
15
|
return;
|
|
16
|
+
}
|
|
16
17
|
const listed = [...known].join(', ');
|
|
17
18
|
const rest = listed
|
|
18
19
|
? `The only skills are: ${listed}. Nothing else needs a skill load — answer or act with the tools you already have.`
|
|
@@ -7,14 +7,15 @@ export type PreToolFold = {
|
|
|
7
7
|
ok: false;
|
|
8
8
|
rejection: HookRejection;
|
|
9
9
|
};
|
|
10
|
+
export interface PostToolFold {
|
|
11
|
+
result: unknown;
|
|
12
|
+
outcome?: ToolExecutionOutcome;
|
|
13
|
+
}
|
|
10
14
|
export declare class HookPipeline {
|
|
11
15
|
private readonly _behaviorHooks;
|
|
12
16
|
constructor(hooks?: readonly HarnessHook[]);
|
|
13
17
|
onRunStart(payload: Omit<RunStartPayload, 'phase'>): Promise<void>;
|
|
14
18
|
onRunEnd(payload: Omit<RunEndPayload, 'phase'>): Promise<void>;
|
|
15
19
|
runPreToolFold(payload: Omit<PreToolCallPayload, 'phase'>): Promise<PreToolFold>;
|
|
16
|
-
runPostToolFold(payload: Omit<PostToolCallPayload, 'phase'>): Promise<
|
|
17
|
-
result: unknown;
|
|
18
|
-
outcome?: ToolExecutionOutcome;
|
|
19
|
-
}>;
|
|
20
|
+
runPostToolFold(payload: Omit<PostToolCallPayload, 'phase'>): Promise<PostToolFold>;
|
|
20
21
|
}
|
|
@@ -9,13 +9,15 @@ export class HookPipeline {
|
|
|
9
9
|
}
|
|
10
10
|
async onRunStart(payload) {
|
|
11
11
|
const folded = await runHooks(this._behaviorHooks, { phase: 'runStart', ...payload });
|
|
12
|
-
if ('guidance' in folded)
|
|
12
|
+
if ('guidance' in folded) {
|
|
13
13
|
hlog('run hook failed', { stage: 'runStart', error: folded.error });
|
|
14
|
+
}
|
|
14
15
|
}
|
|
15
16
|
async onRunEnd(payload) {
|
|
16
17
|
const folded = await runHooks(this._behaviorHooks, { phase: 'runEnd', ...payload });
|
|
17
|
-
if ('guidance' in folded)
|
|
18
|
+
if ('guidance' in folded) {
|
|
18
19
|
hlog('run hook failed', { stage: 'runEnd', error: folded.error });
|
|
20
|
+
}
|
|
19
21
|
}
|
|
20
22
|
async runPreToolFold(payload) {
|
|
21
23
|
const folded = await runHooks(this._behaviorHooks, { phase: 'preToolCall', ...payload });
|
|
@@ -42,8 +44,9 @@ export class HookPipeline {
|
|
|
42
44
|
result = folded.result;
|
|
43
45
|
}
|
|
44
46
|
}
|
|
45
|
-
if (outcome !== undefined)
|
|
47
|
+
if (outcome !== undefined) {
|
|
46
48
|
outcome = normalizeToolExecutionOutcome(result, outcome);
|
|
49
|
+
}
|
|
47
50
|
return { result, outcome };
|
|
48
51
|
}
|
|
49
52
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { errorMessage, isRecord } from '../guards.js';
|
|
1
2
|
import { hlog } from '../log.js';
|
|
2
3
|
function cloneJson(value) {
|
|
3
4
|
try {
|
|
@@ -8,19 +9,20 @@ function cloneJson(value) {
|
|
|
8
9
|
return value;
|
|
9
10
|
}
|
|
10
11
|
}
|
|
11
|
-
function
|
|
12
|
-
return
|
|
12
|
+
function isPlainObject(value) {
|
|
13
|
+
return isRecord(value) && !Array.isArray(value);
|
|
13
14
|
}
|
|
14
15
|
function cloneArgs(args) {
|
|
15
16
|
const cloned = cloneJson(args);
|
|
16
|
-
return
|
|
17
|
+
return isPlainObject(cloned) ? cloned : args;
|
|
17
18
|
}
|
|
18
19
|
function isMessage(value) {
|
|
19
|
-
return
|
|
20
|
+
return isPlainObject(value) && typeof value.role === 'string' && typeof value.content === 'string';
|
|
20
21
|
}
|
|
21
22
|
function freshContext(ctx) {
|
|
22
|
-
if (ctx.phase === 'preToolCall')
|
|
23
|
+
if (ctx.phase === 'preToolCall') {
|
|
23
24
|
return { ...ctx, args: cloneArgs(ctx.args) };
|
|
25
|
+
}
|
|
24
26
|
if (ctx.phase === 'postToolCall') {
|
|
25
27
|
return { ...ctx, args: cloneArgs(ctx.args), result: cloneJson(ctx.result) };
|
|
26
28
|
}
|
|
@@ -52,7 +54,7 @@ function merge(current, returned) {
|
|
|
52
54
|
return current;
|
|
53
55
|
}
|
|
54
56
|
function rejectionOf(current, err) {
|
|
55
|
-
const message =
|
|
57
|
+
const message = errorMessage(err);
|
|
56
58
|
hlog('hook failed', { stage: current.phase, error: message });
|
|
57
59
|
if (current.phase === 'postToolCall') {
|
|
58
60
|
return {
|
|
@@ -69,10 +71,12 @@ export async function runHooks(hooks, ctx) {
|
|
|
69
71
|
continue;
|
|
70
72
|
try {
|
|
71
73
|
const returned = await hook.run(freshContext(current));
|
|
72
|
-
if (!returned || typeof returned !== 'object')
|
|
74
|
+
if (!returned || typeof returned !== 'object') {
|
|
73
75
|
continue;
|
|
74
|
-
|
|
76
|
+
}
|
|
77
|
+
if (isRejection(returned)) {
|
|
75
78
|
return rejection(returned);
|
|
79
|
+
}
|
|
76
80
|
current = merge(current, returned);
|
|
77
81
|
}
|
|
78
82
|
catch (err) {
|
|
@@ -1,20 +1,24 @@
|
|
|
1
|
+
import { isRecord } from './guards.js';
|
|
1
2
|
const EMA_WEIGHT = 0.25;
|
|
2
3
|
const STALL_MS = 2_000;
|
|
3
4
|
const NO_BYTES = { downloaded: 0, total: 0, aggregate: false };
|
|
4
5
|
export function transferProgress(event) {
|
|
5
6
|
const aggregate = aggregateTransfer(event.fileSetInfo) ?? aggregateTransfer(event.shardInfo);
|
|
6
|
-
if (aggregate)
|
|
7
|
+
if (aggregate) {
|
|
7
8
|
return aggregate;
|
|
9
|
+
}
|
|
8
10
|
const bytes = { downloaded: uint(event.downloaded), total: uint(event.total), aggregate: false };
|
|
9
11
|
const reported = reportedPercentage(event.percentage);
|
|
10
|
-
if (reported === null && bytes.downloaded === 0 && bytes.total === 0)
|
|
12
|
+
if (reported === null && bytes.downloaded === 0 && bytes.total === 0) {
|
|
11
13
|
return null;
|
|
14
|
+
}
|
|
12
15
|
return { ...bytes, percentage: resolvePercentage(reported, bytes) };
|
|
13
16
|
}
|
|
14
17
|
export function progressBytes(event) {
|
|
15
18
|
const transfer = transferProgress(event);
|
|
16
|
-
if (!transfer)
|
|
19
|
+
if (!transfer) {
|
|
17
20
|
return NO_BYTES;
|
|
21
|
+
}
|
|
18
22
|
return {
|
|
19
23
|
downloaded: transfer.downloaded,
|
|
20
24
|
total: transfer.total,
|
|
@@ -34,8 +38,9 @@ export class DownloadSpeedSampler {
|
|
|
34
38
|
return 0;
|
|
35
39
|
}
|
|
36
40
|
const elapsedMs = at - this._at;
|
|
37
|
-
if (elapsedMs <= 0)
|
|
41
|
+
if (elapsedMs <= 0) {
|
|
38
42
|
return Math.round(this._bytesPerSecond);
|
|
43
|
+
}
|
|
39
44
|
const delta = bytes.downloaded - this._downloaded;
|
|
40
45
|
if (delta === 0) {
|
|
41
46
|
if (elapsedMs >= STALL_MS) {
|
|
@@ -62,7 +67,7 @@ export class DownloadSpeedSampler {
|
|
|
62
67
|
}
|
|
63
68
|
}
|
|
64
69
|
function aggregateTransfer(value) {
|
|
65
|
-
if (!
|
|
70
|
+
if (!isRecord(value))
|
|
66
71
|
return null;
|
|
67
72
|
const bytes = {
|
|
68
73
|
downloaded: uint(value.overallDownloaded),
|
|
@@ -84,9 +89,6 @@ function reportedPercentage(value) {
|
|
|
84
89
|
function bytesPercentage(bytes) {
|
|
85
90
|
return bytes.total > 0 ? percentage((bytes.downloaded / bytes.total) * 100) : 0;
|
|
86
91
|
}
|
|
87
|
-
function record(value) {
|
|
88
|
-
return typeof value === 'object' && value !== null;
|
|
89
|
-
}
|
|
90
92
|
function uint(value) {
|
|
91
93
|
return typeof value === 'number' && Number.isFinite(value) ? Math.max(0, Math.floor(value)) : 0;
|
|
92
94
|
}
|
|
@@ -2,4 +2,4 @@ import type { ModelRegistryEntry } from '@qvac/sdk';
|
|
|
2
2
|
export type ModelSrc = string | (ModelRegistryEntry & {
|
|
3
3
|
src: string;
|
|
4
4
|
});
|
|
5
|
-
export declare function defaultContextSize(modelSrc: ModelSrc): number;
|
|
5
|
+
export declare function defaultContextSize(modelSrc: ModelSrc, trainedContext?: number): number;
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
const TINY_MODEL_PARAMS_BILLIONS = 0.8;
|
|
2
2
|
const TINY_MODEL_CONTEXT_SIZE = 8_192;
|
|
3
3
|
const DESKTOP_DEFAULT_CONTEXT_SIZE = 51_200;
|
|
4
|
-
export function defaultContextSize(modelSrc) {
|
|
4
|
+
export function defaultContextSize(modelSrc, trainedContext) {
|
|
5
|
+
const size = tieredContextSize(modelSrc);
|
|
6
|
+
return trainedContext ? Math.min(size, trainedContext) : size;
|
|
7
|
+
}
|
|
8
|
+
function tieredContextSize(modelSrc) {
|
|
5
9
|
if (typeof modelSrc === 'string')
|
|
6
10
|
return DESKTOP_DEFAULT_CONTEXT_SIZE;
|
|
7
11
|
const params = Number.parseFloat(modelSrc.params);
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import type { CustomModelEntry } from './model-catalog.ts';
|
|
2
|
+
export interface CustomDownloads {
|
|
3
|
+
readonly files: ReadonlyArray<string>;
|
|
4
|
+
readonly dirs: ReadonlyArray<string>;
|
|
5
|
+
}
|
|
2
6
|
export declare function customFileCachePath(src: string, modelsDir: string | undefined): string | null;
|
|
3
|
-
export
|
|
7
|
+
export interface CustomShardCache {
|
|
8
|
+
readonly dir: string;
|
|
9
|
+
readonly files: ReadonlyArray<string>;
|
|
10
|
+
}
|
|
11
|
+
export declare function customShardCache(src: string, modelsDir: string | undefined): CustomShardCache | null;
|
|
12
|
+
export declare function customDownloads(entry: CustomModelEntry, modelsDir: string | undefined): Promise<CustomDownloads>;
|
|
4
13
|
export declare function isCustomModelCached(entry: CustomModelEntry, modelsDir: string | undefined): Promise<boolean>;
|
|
@@ -2,33 +2,61 @@ import crypto from 'crypto';
|
|
|
2
2
|
import fs from 'fs';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import { isRemoteSource, localSourcePath } from './gguf-header.js';
|
|
5
|
-
|
|
5
|
+
import { shardSet } from './shards.js';
|
|
6
6
|
const ARCHIVE = /\.(tar|tgz|zip)(\.\w+)?$/i;
|
|
7
7
|
export function customFileCachePath(src, modelsDir) {
|
|
8
|
-
if (!isRemoteSource(src))
|
|
8
|
+
if (!isRemoteSource(src)) {
|
|
9
9
|
return localSourcePath(src);
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
}
|
|
11
|
+
const filename = filenameOf(src);
|
|
12
|
+
if (!modelsDir || shardSet(src) || ARCHIVE.test(filename)) {
|
|
12
13
|
return null;
|
|
13
|
-
|
|
14
|
-
return path.join(modelsDir, `${
|
|
14
|
+
}
|
|
15
|
+
return path.join(modelsDir, `${shortHash(src)}_${filename}`);
|
|
15
16
|
}
|
|
16
|
-
export function
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
export function customShardCache(src, modelsDir) {
|
|
18
|
+
const set = shardSet(src);
|
|
19
|
+
if (!modelsDir || !isRemoteSource(src) || !set) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
const dir = path.join(modelsDir, 'sharded', shortHash(`${set.baseUrl}/${set.base}`));
|
|
23
|
+
return { dir, files: set.shards.map((shard) => path.join(dir, shard.filename)) };
|
|
24
|
+
}
|
|
25
|
+
export async function customDownloads(entry, modelsDir) {
|
|
26
|
+
const remote = sourcesOf(entry).filter(isRemoteSource);
|
|
27
|
+
const shardDirs = remote.flatMap((src) => customShardCache(src, modelsDir)?.dir ?? []);
|
|
28
|
+
const inShardDirs = await Promise.all(shardDirs.map(listFiles));
|
|
29
|
+
const singles = remote.flatMap((src) => customFileCachePath(src, modelsDir) ?? []);
|
|
30
|
+
return { files: [...singles, ...inShardDirs.flat()], dirs: shardDirs };
|
|
22
31
|
}
|
|
23
32
|
export async function isCustomModelCached(entry, modelsDir) {
|
|
24
|
-
const
|
|
25
|
-
const sizes = await Promise.all(
|
|
33
|
+
const expected = sourcesOf(entry).flatMap((src) => customShardCache(src, modelsDir)?.files ?? [customFileCachePath(src, modelsDir)]);
|
|
34
|
+
const sizes = await Promise.all(expected.map(onDiskSize));
|
|
26
35
|
const present = sizes.filter((size) => size !== null);
|
|
27
|
-
if (present.length < sizes.length)
|
|
36
|
+
if (present.length < sizes.length) {
|
|
28
37
|
return false;
|
|
38
|
+
}
|
|
29
39
|
const total = present.reduce((sum, size) => sum + size, 0);
|
|
30
40
|
return entry.expectedSize ? total === entry.expectedSize : true;
|
|
31
41
|
}
|
|
42
|
+
function sourcesOf(entry) {
|
|
43
|
+
return entry.projectionSrc ? [entry.src, entry.projectionSrc] : [entry.src];
|
|
44
|
+
}
|
|
45
|
+
function filenameOf(src) {
|
|
46
|
+
return src.split('/').pop()?.split('?')[0] || 'model.gguf';
|
|
47
|
+
}
|
|
48
|
+
function shortHash(input) {
|
|
49
|
+
return crypto.createHash('sha256').update(input, 'utf8').digest('hex').slice(0, 16);
|
|
50
|
+
}
|
|
51
|
+
async function listFiles(dir) {
|
|
52
|
+
try {
|
|
53
|
+
const names = await fs.promises.readdir(dir);
|
|
54
|
+
return names.map((name) => path.join(dir, String(name)));
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
32
60
|
async function onDiskSize(file) {
|
|
33
61
|
if (file === null)
|
|
34
62
|
return null;
|
|
@@ -23,8 +23,9 @@ export declare const GGUF_HEADER_BYTES = 1048576;
|
|
|
23
23
|
export declare const GGUF_HEADER_TIMEOUT_MS = 30000;
|
|
24
24
|
export declare function isRemoteSource(src: string): boolean;
|
|
25
25
|
export declare function localSourcePath(src: string): string | null;
|
|
26
|
-
export
|
|
26
|
+
export interface ReadGgufHeaderOptions {
|
|
27
27
|
fetch?: GgufRangeFetch;
|
|
28
28
|
maxBytes?: number;
|
|
29
|
-
}
|
|
29
|
+
}
|
|
30
|
+
export declare function readGgufHeaderBytes(src: string, opts?: ReadGgufHeaderOptions): Promise<Uint8Array | null>;
|
|
30
31
|
export declare function parseGgufHeader(bytes: Uint8Array): GgufHeader | null;
|
|
@@ -5,6 +5,7 @@ import os from 'os';
|
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import { fileURLToPath } from 'url';
|
|
7
7
|
import defaultFetch from '#fetch';
|
|
8
|
+
const rangeFetch = defaultFetch;
|
|
8
9
|
export const GGUF_HEADER_BYTES = 1_048_576;
|
|
9
10
|
export const GGUF_HEADER_TIMEOUT_MS = 30_000;
|
|
10
11
|
const UINT8 = 0;
|
|
@@ -24,14 +25,17 @@ export function isRemoteSource(src) {
|
|
|
24
25
|
return /^https?:\/\//i.test(src);
|
|
25
26
|
}
|
|
26
27
|
export function localSourcePath(src) {
|
|
27
|
-
if (/^file:/i.test(src))
|
|
28
|
+
if (/^file:/i.test(src)) {
|
|
28
29
|
return filePath(src);
|
|
30
|
+
}
|
|
29
31
|
if (/^[a-z][a-z0-9+.-]+:/i.test(src))
|
|
30
32
|
return null;
|
|
31
|
-
if (src === '~')
|
|
33
|
+
if (src === '~') {
|
|
32
34
|
return os.homedir();
|
|
33
|
-
|
|
35
|
+
}
|
|
36
|
+
if (src.startsWith('~/')) {
|
|
34
37
|
return path.join(os.homedir(), src.slice(2));
|
|
38
|
+
}
|
|
35
39
|
return src;
|
|
36
40
|
}
|
|
37
41
|
function filePath(src) {
|
|
@@ -45,7 +49,7 @@ function filePath(src) {
|
|
|
45
49
|
export function readGgufHeaderBytes(src, opts = {}) {
|
|
46
50
|
const maxBytes = opts.maxBytes ?? GGUF_HEADER_BYTES;
|
|
47
51
|
return isRemoteSource(src)
|
|
48
|
-
? fetchHead(src, maxBytes, opts.fetch ??
|
|
52
|
+
? fetchHead(src, maxBytes, opts.fetch ?? rangeFetch)
|
|
49
53
|
: readLocalHead(src, maxBytes);
|
|
50
54
|
}
|
|
51
55
|
async function fetchHead(src, maxBytes, fetch) {
|
|
@@ -56,11 +60,13 @@ async function fetchHead(src, maxBytes, fetch) {
|
|
|
56
60
|
headers: { Range: `bytes=0-${maxBytes - 1}` },
|
|
57
61
|
signal: controller.signal
|
|
58
62
|
});
|
|
59
|
-
if (!response.ok)
|
|
63
|
+
if (!response.ok) {
|
|
60
64
|
return null;
|
|
65
|
+
}
|
|
61
66
|
const length = response.headers.get('content-length');
|
|
62
|
-
if (length === null || !(Number(length) <= maxBytes))
|
|
67
|
+
if (length === null || !(Number(length) <= maxBytes)) {
|
|
63
68
|
return null;
|
|
69
|
+
}
|
|
64
70
|
return new Uint8Array(await response.arrayBuffer()).subarray(0, maxBytes);
|
|
65
71
|
}
|
|
66
72
|
catch {
|
|
@@ -72,8 +78,9 @@ async function fetchHead(src, maxBytes, fetch) {
|
|
|
72
78
|
}
|
|
73
79
|
async function readLocalHead(src, maxBytes) {
|
|
74
80
|
const file = localSourcePath(src);
|
|
75
|
-
if (file === null)
|
|
81
|
+
if (file === null) {
|
|
76
82
|
return null;
|
|
83
|
+
}
|
|
77
84
|
let handle;
|
|
78
85
|
try {
|
|
79
86
|
handle = await fs.promises.open(file, 'r');
|
|
@@ -98,32 +105,42 @@ export function parseGgufHeader(bytes) {
|
|
|
98
105
|
bytes,
|
|
99
106
|
offset: 16
|
|
100
107
|
};
|
|
101
|
-
if (c.view.getUint32(4, true) < 2)
|
|
108
|
+
if (c.view.getUint32(4, true) < 2) {
|
|
102
109
|
return null;
|
|
110
|
+
}
|
|
103
111
|
const count = readU64(c);
|
|
104
112
|
const header = {};
|
|
105
113
|
const contextLengths = new Map();
|
|
106
114
|
for (let i = 0; i < count; i += 1) {
|
|
107
115
|
const key = readString(c);
|
|
108
|
-
if (key === null || !has(c, 4))
|
|
116
|
+
if (key === null || !has(c, 4)) {
|
|
109
117
|
break;
|
|
118
|
+
}
|
|
110
119
|
const value = readValue(c, readU32(c), key === 'general.tags');
|
|
111
|
-
if (!value.ok)
|
|
120
|
+
if (!value.ok) {
|
|
112
121
|
break;
|
|
113
|
-
|
|
122
|
+
}
|
|
123
|
+
if (key === 'general.architecture') {
|
|
114
124
|
header.architecture = value.str;
|
|
115
|
-
|
|
125
|
+
}
|
|
126
|
+
else if (key === 'general.name') {
|
|
116
127
|
header.name = value.str;
|
|
117
|
-
|
|
128
|
+
}
|
|
129
|
+
else if (key === 'general.type') {
|
|
118
130
|
header.type = value.str;
|
|
119
|
-
|
|
131
|
+
}
|
|
132
|
+
else if (key === 'general.license') {
|
|
120
133
|
header.license = value.str;
|
|
121
|
-
|
|
134
|
+
}
|
|
135
|
+
else if (key === 'general.size_label') {
|
|
122
136
|
header.sizeLabel = value.str;
|
|
123
|
-
|
|
137
|
+
}
|
|
138
|
+
else if (key === 'general.tags') {
|
|
124
139
|
header.tags = value.strs;
|
|
125
|
-
|
|
140
|
+
}
|
|
141
|
+
else if (key.endsWith('.context_length')) {
|
|
126
142
|
contextLengths.set(key, value.num);
|
|
143
|
+
}
|
|
127
144
|
}
|
|
128
145
|
header.contextLength =
|
|
129
146
|
contextLengths.get(`${header.architecture}.context_length`) ??
|
|
@@ -157,17 +174,20 @@ function readValue(c, type, collect = false) {
|
|
|
157
174
|
return str === null ? { ok: false } : { ok: true, str };
|
|
158
175
|
}
|
|
159
176
|
case ARRAY: {
|
|
160
|
-
if (!has(c, 12))
|
|
177
|
+
if (!has(c, 12)) {
|
|
161
178
|
return { ok: false };
|
|
179
|
+
}
|
|
162
180
|
const elementType = readU32(c);
|
|
163
181
|
const length = readU64(c);
|
|
164
182
|
const strs = new Array();
|
|
165
183
|
for (let i = 0; i < length; i += 1) {
|
|
166
184
|
const element = readValue(c, elementType);
|
|
167
|
-
if (!element.ok)
|
|
185
|
+
if (!element.ok) {
|
|
168
186
|
return { ok: false };
|
|
169
|
-
|
|
187
|
+
}
|
|
188
|
+
if (collect && element.str !== undefined) {
|
|
170
189
|
strs.push(element.str);
|
|
190
|
+
}
|
|
171
191
|
}
|
|
172
192
|
return collect ? { ok: true, strs } : { ok: true };
|
|
173
193
|
}
|
|
@@ -176,8 +196,9 @@ function readValue(c, type, collect = false) {
|
|
|
176
196
|
}
|
|
177
197
|
}
|
|
178
198
|
function fixed(c, width, read) {
|
|
179
|
-
if (!has(c, width))
|
|
199
|
+
if (!has(c, width)) {
|
|
180
200
|
return { ok: false };
|
|
201
|
+
}
|
|
181
202
|
const num = read();
|
|
182
203
|
c.offset += width;
|
|
183
204
|
return { ok: true, num };
|
|
@@ -200,8 +221,9 @@ function readString(c) {
|
|
|
200
221
|
if (!has(c, 8))
|
|
201
222
|
return null;
|
|
202
223
|
const length = readU64(c);
|
|
203
|
-
if (!has(c, length))
|
|
224
|
+
if (!has(c, length)) {
|
|
204
225
|
return null;
|
|
226
|
+
}
|
|
205
227
|
const str = b4a.toString(c.bytes.subarray(c.offset, c.offset + length), 'utf8');
|
|
206
228
|
c.offset += length;
|
|
207
229
|
return str;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface IdleReaperOptions {
|
|
2
|
+
sweep: () => Promise<void>;
|
|
3
|
+
waitMs: number;
|
|
4
|
+
onError: (err: unknown) => void;
|
|
5
|
+
now?: () => number;
|
|
6
|
+
tickMs?: number;
|
|
7
|
+
}
|
|
8
|
+
export interface IdleReaper {
|
|
9
|
+
configure(timeoutMs: number): void;
|
|
10
|
+
enter(): Promise<void>;
|
|
11
|
+
exit(): void;
|
|
12
|
+
close(): void;
|
|
13
|
+
}
|
|
14
|
+
export declare function createIdleReaper({ sweep, waitMs, onError, now, tickMs }: IdleReaperOptions): IdleReaper;
|
|
@@ -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
|
}
|