@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
|
@@ -7,18 +7,18 @@ export type DownloadProgressEvent = {
|
|
|
7
7
|
type: 'progress';
|
|
8
8
|
transferred?: boolean;
|
|
9
9
|
} & DownloadProgress;
|
|
10
|
-
export
|
|
10
|
+
export interface DownloadCompleteEvent {
|
|
11
11
|
type: 'complete';
|
|
12
12
|
assetId: string;
|
|
13
13
|
downloaded?: boolean;
|
|
14
|
-
}
|
|
15
|
-
export
|
|
14
|
+
}
|
|
15
|
+
export interface DownloadErrorEvent {
|
|
16
16
|
type: 'error';
|
|
17
17
|
message: string;
|
|
18
|
-
}
|
|
19
|
-
export
|
|
18
|
+
}
|
|
19
|
+
export interface DownloadAbortedEvent {
|
|
20
20
|
type: 'aborted';
|
|
21
|
-
}
|
|
21
|
+
}
|
|
22
22
|
export type DownloadEvent = DownloadProgressEvent | DownloadCompleteEvent | DownloadErrorEvent | DownloadAbortedEvent;
|
|
23
23
|
export interface DownloadSdk extends ModelRegistrySdk {
|
|
24
24
|
downloadAsset(options: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Readable } from 'streamx';
|
|
2
|
-
import { errorMessage } from '../
|
|
2
|
+
import { errorMessage } from '../guards.js';
|
|
3
3
|
import { resolveModelSrc } from '../models/model-source.js';
|
|
4
4
|
const noop = () => { };
|
|
5
5
|
export function download(sdkOrLoader, args, onSettled) {
|
|
@@ -30,12 +30,14 @@ export function download(sdkOrLoader, args, onSettled) {
|
|
|
30
30
|
finish({ type: 'aborted' });
|
|
31
31
|
};
|
|
32
32
|
const onProgress = (p) => {
|
|
33
|
-
if (!settled)
|
|
33
|
+
if (!settled) {
|
|
34
34
|
stream.push({ ...p, type: 'progress', transferred });
|
|
35
|
+
}
|
|
35
36
|
};
|
|
36
37
|
const start = async () => {
|
|
37
|
-
if (signal?.aborted)
|
|
38
|
+
if (signal?.aborted) {
|
|
38
39
|
return finish({ type: 'aborted' });
|
|
40
|
+
}
|
|
39
41
|
try {
|
|
40
42
|
sdkRef = await loadSdk();
|
|
41
43
|
const resolved = await resolveModelSrc(sdkRef, model, addon);
|
|
@@ -44,8 +46,9 @@ export function download(sdkOrLoader, args, onSettled) {
|
|
|
44
46
|
const aggregate = aggregateLayout(srcs, assetSizes);
|
|
45
47
|
let mainAssetId = '';
|
|
46
48
|
for (let i = 0; i < srcs.length; i++) {
|
|
47
|
-
if (signal?.aborted)
|
|
49
|
+
if (signal?.aborted) {
|
|
48
50
|
return finish({ type: 'aborted' });
|
|
51
|
+
}
|
|
49
52
|
const progress = aggregate
|
|
50
53
|
? aggregateProgressHandler(onProgress, {
|
|
51
54
|
setKey: mainSrc,
|
|
@@ -61,23 +64,26 @@ export function download(sdkOrLoader, args, onSettled) {
|
|
|
61
64
|
assetSrc: srcs[i],
|
|
62
65
|
seed,
|
|
63
66
|
onProgress: (update) => {
|
|
64
|
-
if (update.percentage < 100)
|
|
67
|
+
if (update.percentage < 100) {
|
|
65
68
|
transferred = true;
|
|
69
|
+
}
|
|
66
70
|
progress(update);
|
|
67
71
|
}
|
|
68
72
|
});
|
|
69
73
|
requestId = op.requestId;
|
|
70
74
|
const assetId = await op;
|
|
71
|
-
if (i === 0)
|
|
75
|
+
if (i === 0) {
|
|
72
76
|
mainAssetId = assetId;
|
|
77
|
+
}
|
|
73
78
|
}
|
|
74
79
|
opDone = true;
|
|
75
80
|
finish({ type: 'complete', assetId: mainAssetId, downloaded: transferred });
|
|
76
81
|
}
|
|
77
82
|
catch (err) {
|
|
78
83
|
opDone = true;
|
|
79
|
-
if (signal?.aborted)
|
|
84
|
+
if (signal?.aborted) {
|
|
80
85
|
return finish({ type: 'aborted' });
|
|
86
|
+
}
|
|
81
87
|
finish({ type: 'error', message: errorMessage(err) });
|
|
82
88
|
}
|
|
83
89
|
};
|
|
@@ -103,8 +109,9 @@ function aggregateLayout(sources, assetSizes) {
|
|
|
103
109
|
let totalBytes = 0;
|
|
104
110
|
for (const source of sources) {
|
|
105
111
|
const size = assetSizes[source];
|
|
106
|
-
if (!Number.isFinite(size) || size <= 0)
|
|
112
|
+
if (!Number.isFinite(size) || size <= 0) {
|
|
107
113
|
return null;
|
|
114
|
+
}
|
|
108
115
|
offsets.push(totalBytes);
|
|
109
116
|
sizes.push(size);
|
|
110
117
|
totalBytes += size;
|
|
@@ -7,4 +7,9 @@ export interface EnhanceResult {
|
|
|
7
7
|
totalTokens?: number;
|
|
8
8
|
}
|
|
9
9
|
export type Enhancer = (prompt: string, signal?: BareAbortSignal) => Promise<EnhanceResult | null>;
|
|
10
|
-
export
|
|
10
|
+
export interface ExpandImagePromptOptions {
|
|
11
|
+
modelId: string;
|
|
12
|
+
model: string;
|
|
13
|
+
signal?: BareAbortSignal | undefined;
|
|
14
|
+
}
|
|
15
|
+
export declare function expandImagePrompt(sdk: CompletionSdk, prompt: string, { modelId, model, signal }: ExpandImagePromptOptions): Promise<EnhanceResult | null>;
|
|
@@ -3,7 +3,7 @@ import { raceAbort } from '../helpers/race-abort.js';
|
|
|
3
3
|
const SYSTEM = "Rewrite the user's description as a single vivid prompt for an image generator. " +
|
|
4
4
|
'Answer with the prompt alone: no preamble, no quotes, no explanation.';
|
|
5
5
|
const MAX_PROMPT_CHARS = 400;
|
|
6
|
-
export async function expandImagePrompt(sdk, modelId, model,
|
|
6
|
+
export async function expandImagePrompt(sdk, prompt, { modelId, model, signal }) {
|
|
7
7
|
const run = sdk.completion({
|
|
8
8
|
modelId,
|
|
9
9
|
history: [
|
|
@@ -18,12 +18,15 @@ export async function expandImagePrompt(sdk, modelId, model, prompt, signal) {
|
|
|
18
18
|
final = await raceAbort(run.final, signal);
|
|
19
19
|
}
|
|
20
20
|
catch (err) {
|
|
21
|
-
if (run.requestId)
|
|
22
|
-
void sdk.cancel?.({ requestId: run.requestId }).catch(
|
|
21
|
+
if (run.requestId) {
|
|
22
|
+
void sdk.cancel?.({ requestId: run.requestId }).catch(noop);
|
|
23
|
+
}
|
|
23
24
|
throw err;
|
|
24
25
|
}
|
|
25
26
|
const text = cleanAnswer(final.contentText).slice(0, MAX_PROMPT_CHARS);
|
|
26
|
-
if (!text)
|
|
27
|
+
if (!text) {
|
|
27
28
|
return null;
|
|
29
|
+
}
|
|
28
30
|
return { text, model, totalTokens: final.stats?.generatedTokens };
|
|
29
31
|
}
|
|
32
|
+
function noop() { }
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { errorMessage } from '../guards.js';
|
|
1
2
|
import { AbortedError } from '../helpers/race-abort.js';
|
|
2
3
|
const CAPABILITY_TOOLS = {
|
|
3
4
|
image: { tool: 'generate_image', enhances: 'prompt' },
|
|
4
5
|
translate: { tool: 'translate' }
|
|
5
6
|
};
|
|
6
|
-
export const CAPABILITIES = Object.keys(CAPABILITY_TOOLS);
|
|
7
|
+
export const CAPABILITIES = Object.keys(CAPABILITY_TOOLS).filter(isCapability);
|
|
7
8
|
export function isCapability(name) {
|
|
8
9
|
return name in CAPABILITY_TOOLS;
|
|
9
10
|
}
|
|
@@ -30,13 +31,15 @@ export async function* invoke({ capability, args, tools, ctx, enhance = 'never',
|
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
|
-
if (ctx.signal?.aborted)
|
|
34
|
+
if (ctx.signal?.aborted) {
|
|
34
35
|
return yield { type: 'aborted' };
|
|
36
|
+
}
|
|
35
37
|
yield { type: 'tool-call', name: entry.tool, args: called, effect: tool.effect(called, ctx) };
|
|
36
38
|
try {
|
|
37
39
|
const result = await tool.execute(called, ctx);
|
|
38
|
-
if (ctx.signal?.aborted)
|
|
40
|
+
if (ctx.signal?.aborted) {
|
|
39
41
|
return yield { type: 'aborted' };
|
|
42
|
+
}
|
|
40
43
|
yield { type: 'tool-result', name: entry.tool, result };
|
|
41
44
|
}
|
|
42
45
|
catch (err) {
|
|
@@ -44,7 +47,7 @@ export async function* invoke({ capability, args, tools, ctx, enhance = 'never',
|
|
|
44
47
|
yield { type: 'aborted' };
|
|
45
48
|
return;
|
|
46
49
|
}
|
|
47
|
-
yield { type: 'error', message:
|
|
50
|
+
yield { type: 'error', message: errorMessage(err) };
|
|
48
51
|
return;
|
|
49
52
|
}
|
|
50
53
|
yield {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { errorMessage } from '../guards.js';
|
|
1
2
|
export async function deleteAllKvCaches(loadSdk) {
|
|
2
3
|
return deleteCacheWith(loadSdk, { all: true });
|
|
3
4
|
}
|
|
@@ -15,7 +16,7 @@ async function deleteCacheWith(loadSdk, params) {
|
|
|
15
16
|
catch (error) {
|
|
16
17
|
return {
|
|
17
18
|
status: 'failure',
|
|
18
|
-
error:
|
|
19
|
+
error: errorMessage(error)
|
|
19
20
|
};
|
|
20
21
|
}
|
|
21
22
|
}
|
|
@@ -48,13 +48,15 @@ export interface FitQuery {
|
|
|
48
48
|
}
|
|
49
49
|
export interface PreviewDeps {
|
|
50
50
|
fetch?: PreviewFetch;
|
|
51
|
-
stat?(path: string): Promise<
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
51
|
+
stat?(path: string): Promise<FileStat | null>;
|
|
52
|
+
assessFit?(query: FitQuery): Promise<FitAssessment>;
|
|
53
|
+
}
|
|
54
|
+
export interface FileStat {
|
|
55
|
+
size: number;
|
|
56
|
+
}
|
|
57
|
+
export interface FitAssessment {
|
|
58
|
+
fit: ModelFitVerdict;
|
|
59
|
+
fitReasons: string[];
|
|
58
60
|
}
|
|
59
61
|
interface HuggingFaceRef {
|
|
60
62
|
repo: string;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import defaultFetch from '#fetch';
|
|
3
|
+
import { errorMessage } from '../guards.js';
|
|
3
4
|
import { defaultContextSize } from '../models/context.js';
|
|
4
5
|
import { isRemoteSource, localSourcePath, parseGgufHeader, readGgufHeaderBytes } from '../models/gguf-header.js';
|
|
6
|
+
import { shardSet } from '../models/shards.js';
|
|
5
7
|
const HUGGING_FACE = 'https://huggingface.co';
|
|
6
8
|
const HUGGING_FACE_HOSTS = new Set(['huggingface.co', 'www.huggingface.co', 'hf.co']);
|
|
7
9
|
const NON_MODEL_NAMESPACES = new Set(['api', 'datasets', 'spaces', 'docs', 'models']);
|
|
@@ -32,11 +34,13 @@ export async function previewModelSource(context, deps = {}) {
|
|
|
32
34
|
return refuse('invalid-source', 'Paste a Hugging Face link, a direct link to a .gguf file, or a local path.');
|
|
33
35
|
}
|
|
34
36
|
const weight = await inspectModelFile(src, fetch, deps);
|
|
35
|
-
if ('answer' in weight)
|
|
37
|
+
if ('answer' in weight) {
|
|
36
38
|
return weight.answer;
|
|
39
|
+
}
|
|
37
40
|
const problem = modelProblem(weight.header);
|
|
38
|
-
if (problem)
|
|
41
|
+
if (problem) {
|
|
39
42
|
return refuse(problem[0], problem[1]);
|
|
43
|
+
}
|
|
40
44
|
const taskType = taskTypeFor({
|
|
41
45
|
pipelineTag: weight.file.pipelineTag,
|
|
42
46
|
tags: [...(weight.file.tags ?? []), ...(weight.header.tags ?? [])],
|
|
@@ -58,7 +62,7 @@ export async function previewModelSource(context, deps = {}) {
|
|
|
58
62
|
projectionBytes = projection.file.sizeBytes;
|
|
59
63
|
projectionSrc = projection.file.src;
|
|
60
64
|
}
|
|
61
|
-
const { fit, fitReasons } = await assess(weight
|
|
65
|
+
const { fit, fitReasons } = await assess(weight, taskType, deps);
|
|
62
66
|
return defined({
|
|
63
67
|
ok: true,
|
|
64
68
|
src: weight.file.src,
|
|
@@ -105,14 +109,17 @@ export function parseHuggingFaceRef(src) {
|
|
|
105
109
|
catch {
|
|
106
110
|
return null;
|
|
107
111
|
}
|
|
108
|
-
if (!HUGGING_FACE_HOSTS.has(url.hostname))
|
|
112
|
+
if (!HUGGING_FACE_HOSTS.has(url.hostname)) {
|
|
109
113
|
return null;
|
|
114
|
+
}
|
|
110
115
|
const segments = pathSegments(url.pathname);
|
|
111
|
-
if (!segments)
|
|
116
|
+
if (!segments) {
|
|
112
117
|
return null;
|
|
118
|
+
}
|
|
113
119
|
const [org, name, kind, revision, ...rest] = segments;
|
|
114
|
-
if (!org || !name || NON_MODEL_NAMESPACES.has(org))
|
|
120
|
+
if (!org || !name || NON_MODEL_NAMESPACES.has(org)) {
|
|
115
121
|
return null;
|
|
122
|
+
}
|
|
116
123
|
const repo = `${org}/${name}`;
|
|
117
124
|
if (!kind) {
|
|
118
125
|
const shown = url.searchParams.get('show_file_info');
|
|
@@ -121,17 +128,17 @@ export function parseHuggingFaceRef(src) {
|
|
|
121
128
|
if ((kind === 'blob' || kind === 'resolve') && revision && rest.length > 0) {
|
|
122
129
|
return { repo, revision, file: rest.join('/') };
|
|
123
130
|
}
|
|
124
|
-
if (kind === 'tree' && revision)
|
|
131
|
+
if (kind === 'tree' && revision) {
|
|
125
132
|
return { repo, revision };
|
|
133
|
+
}
|
|
126
134
|
return null;
|
|
127
135
|
}
|
|
128
136
|
async function inspectModelFile(src, fetch, deps) {
|
|
129
137
|
const inspection = await inspect(src, fetch, deps);
|
|
130
|
-
if (inspection.kind === 'answer')
|
|
138
|
+
if (inspection.kind === 'answer') {
|
|
131
139
|
return { answer: inspection.preview };
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
});
|
|
140
|
+
}
|
|
141
|
+
const bytes = await readGgufHeaderBytes(inspection.file.src, { fetch });
|
|
135
142
|
if (!bytes) {
|
|
136
143
|
return {
|
|
137
144
|
answer: refuse('unreachable', 'Could not read the start of the file to check it is a model.')
|
|
@@ -147,8 +154,9 @@ async function inspectModelFile(src, fetch, deps) {
|
|
|
147
154
|
}
|
|
148
155
|
function inspect(src, fetch, deps) {
|
|
149
156
|
const ref = parseHuggingFaceRef(src);
|
|
150
|
-
if (ref)
|
|
157
|
+
if (ref) {
|
|
151
158
|
return inspectHuggingFace(ref, fetch);
|
|
159
|
+
}
|
|
152
160
|
if (isRemoteSource(src)) {
|
|
153
161
|
return wellFormedUrl(src)
|
|
154
162
|
? inspectUrl(src, fetch)
|
|
@@ -191,8 +199,9 @@ async function inspectHuggingFace(ref, fetch) {
|
|
|
191
199
|
const wanted = ref.file;
|
|
192
200
|
if (wanted) {
|
|
193
201
|
const sibling = siblings.find((entry) => entry.rfilename === wanted);
|
|
194
|
-
if (!sibling)
|
|
202
|
+
if (!sibling) {
|
|
195
203
|
return answer(refuse('not-found', `${ref.repo} has no file ${wanted}.`));
|
|
204
|
+
}
|
|
196
205
|
if (!/\.gguf$/i.test(wanted)) {
|
|
197
206
|
return answer(refuse('not-gguf', `${wanted} is not a GGUF file. Only GGUF models run on this device.`));
|
|
198
207
|
}
|
|
@@ -236,15 +245,45 @@ async function inspectUrl(src, fetch) {
|
|
|
236
245
|
if ((response.headers.get('content-type') ?? '').includes('text/html')) {
|
|
237
246
|
return answer(refuse('web-page', 'This link opens a web page, not a model file. Link to the .gguf file itself.'));
|
|
238
247
|
}
|
|
239
|
-
const
|
|
248
|
+
const set = shardSet(src);
|
|
249
|
+
if (set && set.shards.length > 1) {
|
|
250
|
+
return inspectShards(set, fetch);
|
|
251
|
+
}
|
|
252
|
+
return { kind: 'file', file: { src, label: basename(src), sizeBytes: sizeOfResponse(response) } };
|
|
253
|
+
}
|
|
254
|
+
async function inspectShards(set, fetch) {
|
|
255
|
+
let responses;
|
|
256
|
+
try {
|
|
257
|
+
responses = await Promise.all(set.shards.map((shard) => fetch(shard.url, { method: 'HEAD', redirect: 'follow' })));
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
return answer(refuse('unreachable', `Could not reach every part of ${set.base}.`));
|
|
261
|
+
}
|
|
262
|
+
const missing = responses.findIndex((response) => !response.ok);
|
|
263
|
+
if (missing !== -1) {
|
|
264
|
+
const { status } = responses[missing];
|
|
265
|
+
return answer(refuse(status === 404 || status === 410 ? 'not-found' : 'unreachable', `Part ${missing + 1} of ${set.shards.length}, ${set.shards[missing].filename}, answered HTTP ${status}.`));
|
|
266
|
+
}
|
|
267
|
+
const sizes = responses.map(sizeOfResponse);
|
|
268
|
+
return {
|
|
269
|
+
kind: 'file',
|
|
270
|
+
file: {
|
|
271
|
+
src: set.shards[0].url,
|
|
272
|
+
label: `${set.base}${set.extension} (${set.shards.length} parts)`,
|
|
273
|
+
sizeBytes: sizes.includes(0) ? 0 : sizes.reduce((sum, size) => sum + size, 0)
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
function sizeOfResponse(response) {
|
|
278
|
+
return (positive(response.headers.get('x-linked-size')) ??
|
|
240
279
|
positive(response.headers.get('content-length')) ??
|
|
241
|
-
0;
|
|
242
|
-
return { kind: 'file', file: { src, label: basename(src), sizeBytes } };
|
|
280
|
+
0);
|
|
243
281
|
}
|
|
244
282
|
async function inspectLocal(src, file, deps) {
|
|
245
283
|
const stat = await (deps.stat ?? statFile)(file);
|
|
246
|
-
if (!stat)
|
|
284
|
+
if (!stat) {
|
|
247
285
|
return answer(refuse('not-found', `There is no file at ${file}.`));
|
|
286
|
+
}
|
|
248
287
|
return { kind: 'file', file: { src, label: basename(file), sizeBytes: stat.size } };
|
|
249
288
|
}
|
|
250
289
|
async function statFile(file) {
|
|
@@ -261,8 +300,9 @@ function modelFiles(ref, siblings) {
|
|
|
261
300
|
const shardSets = new Map();
|
|
262
301
|
for (const sibling of siblings) {
|
|
263
302
|
const name = sibling.rfilename;
|
|
264
|
-
if (!/\.gguf$/i.test(name) || /mmproj/i.test(name))
|
|
303
|
+
if (!/\.gguf$/i.test(name) || /mmproj/i.test(name)) {
|
|
265
304
|
continue;
|
|
305
|
+
}
|
|
266
306
|
const shard = SHARD.exec(name);
|
|
267
307
|
if (!shard) {
|
|
268
308
|
singles.push({ ...fileOf(ref, sibling), members: [name] });
|
|
@@ -298,8 +338,9 @@ function modelProblem(header) {
|
|
|
298
338
|
'This is a vision projection (mmproj), not a model. Add the model file and pass this as its projection.'
|
|
299
339
|
];
|
|
300
340
|
}
|
|
301
|
-
if (header.type === 'adapter')
|
|
341
|
+
if (header.type === 'adapter') {
|
|
302
342
|
return ['not-a-model', 'This is a LoRA adapter, not a model.'];
|
|
343
|
+
}
|
|
303
344
|
return null;
|
|
304
345
|
}
|
|
305
346
|
function isProjection(header) {
|
|
@@ -307,28 +348,32 @@ function isProjection(header) {
|
|
|
307
348
|
}
|
|
308
349
|
function taskTypeFor({ pipelineTag, tags = [], architecture }) {
|
|
309
350
|
const tagged = [pipelineTag, ...tags].find((tag) => tag !== undefined && Object.hasOwn(PIPELINE_TASKS, tag));
|
|
310
|
-
if (tagged)
|
|
351
|
+
if (tagged) {
|
|
311
352
|
return PIPELINE_TASKS[tagged];
|
|
353
|
+
}
|
|
312
354
|
return ARCHITECTURE_TASKS.find(([pattern]) => pattern.test(architecture ?? ''))?.[1] ?? 'llm';
|
|
313
355
|
}
|
|
314
|
-
async function assess(file, header, taskType, deps) {
|
|
315
|
-
if (taskType !== 'llm')
|
|
356
|
+
async function assess({ file, header }, taskType, deps) {
|
|
357
|
+
if (taskType !== 'llm') {
|
|
316
358
|
return { fit: 'unknown', fitReasons: [NOT_LLM_REASON] };
|
|
317
|
-
|
|
359
|
+
}
|
|
360
|
+
if (!file.sha256) {
|
|
318
361
|
return { fit: 'unknown', fitReasons: [NO_CHECKSUM_REASON] };
|
|
319
|
-
|
|
362
|
+
}
|
|
363
|
+
if (!deps.assessFit) {
|
|
320
364
|
return { fit: 'unknown', fitReasons: [NO_ESTIMATOR_REASON] };
|
|
365
|
+
}
|
|
321
366
|
try {
|
|
322
367
|
return await deps.assessFit({
|
|
323
368
|
sha256Checksum: file.sha256,
|
|
324
369
|
name: header.name ?? file.label,
|
|
325
|
-
contextTokens:
|
|
370
|
+
contextTokens: defaultContextSize(file.src, header.contextLength)
|
|
326
371
|
});
|
|
327
372
|
}
|
|
328
373
|
catch (err) {
|
|
329
374
|
return {
|
|
330
375
|
fit: 'unknown',
|
|
331
|
-
fitReasons: [`The fit estimate failed: ${
|
|
376
|
+
fitReasons: [`The fit estimate failed: ${errorMessage(err)}`]
|
|
332
377
|
};
|
|
333
378
|
}
|
|
334
379
|
}
|
|
@@ -360,8 +405,9 @@ function wellFormedUrl(src) {
|
|
|
360
405
|
}
|
|
361
406
|
function licenseOf(info) {
|
|
362
407
|
const license = info.cardData?.license;
|
|
363
|
-
if (Array.isArray(license))
|
|
408
|
+
if (Array.isArray(license)) {
|
|
364
409
|
return license.length ? license.join(', ') : undefined;
|
|
410
|
+
}
|
|
365
411
|
return license || undefined;
|
|
366
412
|
}
|
|
367
413
|
function sizeOf(sibling) {
|
|
@@ -383,5 +429,11 @@ function answer(preview) {
|
|
|
383
429
|
return { kind: 'answer', preview };
|
|
384
430
|
}
|
|
385
431
|
function defined(value) {
|
|
386
|
-
|
|
432
|
+
const copy = { ...value };
|
|
433
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
434
|
+
if (entry === undefined) {
|
|
435
|
+
Reflect.deleteProperty(copy, key);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
return copy;
|
|
387
439
|
}
|
|
@@ -31,9 +31,9 @@ function verbalize(text, lang) {
|
|
|
31
31
|
let spoken = text.replace(/#(?=\d)/g, ' number ');
|
|
32
32
|
for (const [symbol, code] of CURRENCY_CODES) {
|
|
33
33
|
spoken = spoken.replace(amountAfter(symbol), (_match, amount) => {
|
|
34
|
-
return ` ${amount} ${currencyName(code, lang, amount === '1')} `;
|
|
34
|
+
return ` ${amount} ${currencyName(code, lang, { singular: amount === '1' })} `;
|
|
35
35
|
});
|
|
36
|
-
spoken = spoken.split(symbol).join(` ${currencyName(code, lang
|
|
36
|
+
spoken = spoken.split(symbol).join(` ${currencyName(code, lang)} `);
|
|
37
37
|
}
|
|
38
38
|
for (const [symbol, spokenForm] of SPEECH_LEXICON[lang]) {
|
|
39
39
|
spoken = spoken.split(symbol).join(spokenForm);
|
|
@@ -46,11 +46,12 @@ function amountAfter(symbol) {
|
|
|
46
46
|
function escapeRegExp(text) {
|
|
47
47
|
return text.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&');
|
|
48
48
|
}
|
|
49
|
-
function currencyName(code, lang, singular) {
|
|
49
|
+
function currencyName(code, lang, { singular = false } = {}) {
|
|
50
50
|
const key = `${lang}:${code}:${singular}`;
|
|
51
51
|
const hit = CURRENCY_NAMES.get(key);
|
|
52
|
-
if (hit !== undefined)
|
|
52
|
+
if (hit !== undefined) {
|
|
53
53
|
return hit;
|
|
54
|
+
}
|
|
54
55
|
const parts = new Intl.NumberFormat(lang, {
|
|
55
56
|
style: 'currency',
|
|
56
57
|
currency: code,
|
|
@@ -13,12 +13,10 @@ export function collectToolGrants(skills) {
|
|
|
13
13
|
const owners = grants.grantedOwners.get(name) ?? new Set();
|
|
14
14
|
owners.add(skill.name);
|
|
15
15
|
grants.grantedOwners.set(name, owners);
|
|
16
|
-
if (scope) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
grants.grantedOps.set(scope.toLowerCase(), list);
|
|
21
|
-
}
|
|
16
|
+
if (scope && skill.cliValidator && skill.cliValidator.bin === scope.toLowerCase()) {
|
|
17
|
+
const list = grants.grantedOps.get(scope.toLowerCase()) ?? [];
|
|
18
|
+
list.push(skill.cliValidator);
|
|
19
|
+
grants.grantedOps.set(scope.toLowerCase(), list);
|
|
22
20
|
}
|
|
23
21
|
}
|
|
24
22
|
}
|
|
@@ -49,12 +47,15 @@ export function enabledTools(tools, { toolsSelected, allowlist, grantedNames, gr
|
|
|
49
47
|
}
|
|
50
48
|
if (tool.rootsRequired)
|
|
51
49
|
return hasRoots;
|
|
52
|
-
if (tool.writeRootsRequired)
|
|
50
|
+
if (tool.writeRootsRequired) {
|
|
53
51
|
return hasWriteRoots;
|
|
54
|
-
|
|
52
|
+
}
|
|
53
|
+
if (tool.skillGated) {
|
|
55
54
|
return loadedGrantedNames.has(tool.name);
|
|
56
|
-
|
|
55
|
+
}
|
|
56
|
+
if (!toolsSelected) {
|
|
57
57
|
return true;
|
|
58
|
+
}
|
|
58
59
|
return allowlist.includes(tool.name) || grantedNames.has(tool.name);
|
|
59
60
|
});
|
|
60
61
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isRecord } from '../guards.js';
|
|
1
2
|
import { SKILL_TOOL_NAME } from './tool-names.js';
|
|
2
3
|
export const DIRECT_CALL_ID = 'call-direct';
|
|
3
4
|
export const TOOL_CONTINUATION_NUDGE = "[Tool results above. Continue the user's request: call the next tool, or answer.]";
|
|
@@ -13,37 +14,43 @@ export function skillLoadedTurn(name) {
|
|
|
13
14
|
function refFrom(value) {
|
|
14
15
|
if (!value || typeof value !== 'object')
|
|
15
16
|
return null;
|
|
16
|
-
|
|
17
|
-
if (typeof record.attachmentId !== 'string')
|
|
17
|
+
if (!('attachmentId' in value) || typeof value.attachmentId !== 'string') {
|
|
18
18
|
return null;
|
|
19
|
-
|
|
20
|
-
const
|
|
19
|
+
}
|
|
20
|
+
const ref = { attachmentId: value.attachmentId };
|
|
21
|
+
const name = 'fileName' in value && typeof value.fileName === 'string' ? value.fileName : '';
|
|
21
22
|
const dot = name.lastIndexOf('.');
|
|
22
|
-
if (dot > 0)
|
|
23
|
+
if (dot > 0) {
|
|
23
24
|
ref.type = name.slice(dot + 1).toLowerCase();
|
|
25
|
+
}
|
|
24
26
|
return ref;
|
|
25
27
|
}
|
|
26
28
|
export function attachmentTurn(name, result) {
|
|
27
29
|
const direct = refFrom(result);
|
|
28
|
-
if (direct)
|
|
30
|
+
if (direct) {
|
|
29
31
|
return toolResultTurn(name, DIRECT_CALL_ID, direct);
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
}
|
|
33
|
+
const listed = isRecord(result) ? result.attachments : undefined;
|
|
34
|
+
if (!Array.isArray(listed)) {
|
|
32
35
|
return null;
|
|
36
|
+
}
|
|
33
37
|
const refs = [];
|
|
34
38
|
for (const entry of listed) {
|
|
35
39
|
const ref = refFrom(entry);
|
|
36
|
-
if (ref)
|
|
40
|
+
if (ref) {
|
|
37
41
|
refs.push(ref);
|
|
42
|
+
}
|
|
38
43
|
}
|
|
39
|
-
if (!refs.length)
|
|
44
|
+
if (!refs.length) {
|
|
40
45
|
return null;
|
|
46
|
+
}
|
|
41
47
|
return toolResultTurn(name, DIRECT_CALL_ID, { attachments: refs });
|
|
42
48
|
}
|
|
43
49
|
export function loadedSkillsFrom(messages) {
|
|
44
50
|
const loaded = new Set();
|
|
45
|
-
for (const { name } of skillLoadPayloads(messages))
|
|
51
|
+
for (const { name } of skillLoadPayloads(messages)) {
|
|
46
52
|
loaded.add(name);
|
|
53
|
+
}
|
|
47
54
|
return loaded;
|
|
48
55
|
}
|
|
49
56
|
export function loadedSkillFilesFrom(messages) {
|
|
@@ -66,21 +73,27 @@ export function withoutSkillLoadTurns(messages, name) {
|
|
|
66
73
|
function* skillLoadPayloads(messages) {
|
|
67
74
|
for (const turn of messages) {
|
|
68
75
|
const payload = skillLoadPayload(turn);
|
|
69
|
-
if (payload)
|
|
76
|
+
if (payload) {
|
|
70
77
|
yield payload;
|
|
78
|
+
}
|
|
71
79
|
}
|
|
72
80
|
}
|
|
73
81
|
function skillLoadPayload(turn) {
|
|
74
82
|
if (turn.role !== 'tool')
|
|
75
83
|
return null;
|
|
76
84
|
const text = String(turn.content ?? '');
|
|
77
|
-
if (!text.startsWith(`[Tool: ${SKILL_TOOL_NAME} (`))
|
|
85
|
+
if (!text.startsWith(`[Tool: ${SKILL_TOOL_NAME} (`)) {
|
|
78
86
|
return null;
|
|
87
|
+
}
|
|
79
88
|
try {
|
|
80
89
|
const payload = JSON.parse(text.slice(text.indexOf('\n') + 1));
|
|
81
|
-
if (typeof payload
|
|
90
|
+
if (typeof payload !== 'object' || payload === null) {
|
|
82
91
|
return null;
|
|
83
|
-
|
|
92
|
+
}
|
|
93
|
+
if (!('name' in payload) || typeof payload.name !== 'string') {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
return 'file' in payload && typeof payload.file === 'string'
|
|
84
97
|
? { name: payload.name, file: payload.file }
|
|
85
98
|
: { name: payload.name };
|
|
86
99
|
}
|
|
@@ -95,7 +108,8 @@ function historyPayload(output) {
|
|
|
95
108
|
if (!HOST_ONLY_KEYS.some((key) => key in output))
|
|
96
109
|
return output;
|
|
97
110
|
const rest = { ...output };
|
|
98
|
-
for (const key of HOST_ONLY_KEYS)
|
|
111
|
+
for (const key of HOST_ONLY_KEYS) {
|
|
99
112
|
delete rest[key];
|
|
113
|
+
}
|
|
100
114
|
return rest;
|
|
101
115
|
}
|
|
@@ -27,8 +27,9 @@ export function usageBreakdown(chars, totalTokens, modelName) {
|
|
|
27
27
|
: 0
|
|
28
28
|
};
|
|
29
29
|
const prompt = rows.systemPrompt + rows.agentInstructions + rows.activeSkills + rows.tools;
|
|
30
|
-
if (prompt > totalTokens)
|
|
30
|
+
if (prompt > totalTokens) {
|
|
31
31
|
return scaledToWindow(rows, totalTokens);
|
|
32
|
+
}
|
|
32
33
|
return { ...rows, conversation: totalTokens - prompt, totalTokens };
|
|
33
34
|
}
|
|
34
35
|
function scaledToWindow(rows, totalTokens) {
|
|
@@ -71,7 +71,11 @@ export interface SpeakStreamContext {
|
|
|
71
71
|
export type VoiceLane = <T>(job: () => Promise<T>) => Promise<T>;
|
|
72
72
|
export declare function createVoiceLane(): VoiceLane;
|
|
73
73
|
export declare function transcribeOnce(sdk: VoiceSdk, modelId: string, audio: Buffer): Promise<string>;
|
|
74
|
-
export
|
|
74
|
+
export interface TranscribeStreamingOptions {
|
|
75
|
+
modelId: string;
|
|
76
|
+
signal?: BareAbortSignal | undefined;
|
|
77
|
+
}
|
|
78
|
+
export declare function transcribeStreaming(sdk: VoiceSdk, pcm: Uint8Array, { modelId, signal }: TranscribeStreamingOptions): Promise<string>;
|
|
75
79
|
export declare function speakStreamOnce(sdk: VoiceSdk, modelId: string, text: AsyncIterable<string>): AsyncGenerator<SpeakResult>;
|
|
76
80
|
export declare function speakable(text: string): string;
|
|
77
81
|
export declare function speakOnce(sdk: VoiceSdk, modelId: string, text: string): Promise<number[]>;
|