@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
package/dist-lib/lib/connect.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import EventEmitter from 'events';
|
|
2
2
|
import fs from 'fs';
|
|
3
|
+
import { z } from 'zod';
|
|
3
4
|
import { settleOnClose } from './rpc-session.js';
|
|
4
5
|
import { harnessClient } from '../spec/calls.js';
|
|
5
6
|
import HRPC from '../spec/hrpc/index.js';
|
|
6
7
|
import { unsupportedKvCacheDeletion } from './capabilities/kv-cache.js';
|
|
8
|
+
import { readModelSourcePreview } from './capabilities/preview-model-source.js';
|
|
7
9
|
import { hlog } from './log.js';
|
|
8
10
|
import { assertEmbedDevice } from './models/embed-config.js';
|
|
9
|
-
import { errorCode, errorMessage } from './
|
|
11
|
+
import { errorCode, errorMessage, isRecord } from './guards.js';
|
|
10
12
|
import { pushQueue } from './queue.js';
|
|
11
13
|
import { stageFile, sweepStaging } from './staging.js';
|
|
12
14
|
import { readInstall, readSetup } from './tools/skills/manifest-parse.js';
|
|
@@ -18,9 +20,10 @@ export function connectHarness(transport) {
|
|
|
18
20
|
return new RemoteHarness(transport);
|
|
19
21
|
}
|
|
20
22
|
export function readEmbeddingDeviceResponse(response) {
|
|
21
|
-
const device =
|
|
22
|
-
if (typeof device !== 'string')
|
|
23
|
+
const device = isRecord(response) ? response.device : undefined;
|
|
24
|
+
if (typeof device !== 'string') {
|
|
23
25
|
throw new Error('invalid embedding device response');
|
|
26
|
+
}
|
|
24
27
|
assertEmbedDevice(device);
|
|
25
28
|
return device;
|
|
26
29
|
}
|
|
@@ -35,8 +38,9 @@ export class RemoteHarness extends EventEmitter {
|
|
|
35
38
|
this._transport = transport;
|
|
36
39
|
}
|
|
37
40
|
_ensure() {
|
|
38
|
-
if (this._closed)
|
|
41
|
+
if (this._closed) {
|
|
39
42
|
return Promise.reject(died('harness closed'));
|
|
43
|
+
}
|
|
40
44
|
if (this._session) {
|
|
41
45
|
return this._session.dead
|
|
42
46
|
? Promise.reject(died('harness is dead'))
|
|
@@ -71,8 +75,9 @@ export class RemoteHarness extends EventEmitter {
|
|
|
71
75
|
});
|
|
72
76
|
stream.on('close', () => {
|
|
73
77
|
session.dead = true;
|
|
74
|
-
if (this._closed)
|
|
78
|
+
if (this._closed) {
|
|
75
79
|
return;
|
|
80
|
+
}
|
|
76
81
|
this.emit('status', streamError ? { state: 'died', ...errorDetails(streamError) } : { state: 'died' });
|
|
77
82
|
});
|
|
78
83
|
this._session = session;
|
|
@@ -137,8 +142,9 @@ export class RemoteHarness extends EventEmitter {
|
|
|
137
142
|
let closed = false;
|
|
138
143
|
let received = 0;
|
|
139
144
|
const reclaim = () => {
|
|
140
|
-
|
|
141
|
-
void fs.promises.unlink(
|
|
145
|
+
for (const file of staged.splice(0).reverse()) {
|
|
146
|
+
void fs.promises.unlink(file).catch(noop);
|
|
147
|
+
}
|
|
142
148
|
};
|
|
143
149
|
const onAbort = () => duplex?.destroy();
|
|
144
150
|
try {
|
|
@@ -156,18 +162,19 @@ export class RemoteHarness extends EventEmitter {
|
|
|
156
162
|
if (event.type !== 'content' && event.type !== 'thinking') {
|
|
157
163
|
hlog('client frame', { type: event.type, n: received });
|
|
158
164
|
}
|
|
159
|
-
if (event.type === 'done')
|
|
165
|
+
if (event.type === 'done') {
|
|
160
166
|
break;
|
|
167
|
+
}
|
|
161
168
|
if (event.type === 'approval-ask') {
|
|
162
169
|
const callId = event.callId;
|
|
163
170
|
void Promise.resolve()
|
|
164
171
|
.then(() => context.approve?.({
|
|
165
172
|
name: event.name ?? '',
|
|
166
|
-
arguments: (event.arguments
|
|
173
|
+
arguments: isRecord(event.arguments) ? event.arguments : {},
|
|
167
174
|
resource: event.resource ?? null,
|
|
168
175
|
effect: event.effect === 'read' ? 'read' : 'write',
|
|
169
176
|
intent: event.intent || null,
|
|
170
|
-
display: event.display
|
|
177
|
+
display: isToolCallDisplay(event.display) ? event.display : null
|
|
171
178
|
}))
|
|
172
179
|
.then((approved) => {
|
|
173
180
|
if (!closed) {
|
|
@@ -185,8 +192,9 @@ export class RemoteHarness extends EventEmitter {
|
|
|
185
192
|
const callId = event.callId;
|
|
186
193
|
void bridgeAttach(event, context.attach)
|
|
187
194
|
.then((frame) => {
|
|
188
|
-
if (!closed)
|
|
195
|
+
if (!closed) {
|
|
189
196
|
duplex.write({ ...frame, callId });
|
|
197
|
+
}
|
|
190
198
|
}, (err) => {
|
|
191
199
|
if (!closed) {
|
|
192
200
|
duplex.write({
|
|
@@ -203,12 +211,14 @@ export class RemoteHarness extends EventEmitter {
|
|
|
203
211
|
const callId = event.callId;
|
|
204
212
|
void bridgeFetch(event, context, staged)
|
|
205
213
|
.then((frame) => {
|
|
206
|
-
if (closed)
|
|
214
|
+
if (closed) {
|
|
207
215
|
return reclaim();
|
|
216
|
+
}
|
|
208
217
|
duplex.write({ ...frame, callId });
|
|
209
218
|
}, (err) => {
|
|
210
|
-
if (closed)
|
|
219
|
+
if (closed) {
|
|
211
220
|
return reclaim();
|
|
221
|
+
}
|
|
212
222
|
duplex.write({ type: 'fetch-result', callId, message: errorMessage(err) });
|
|
213
223
|
})
|
|
214
224
|
.catch((err) => hlog('fetch reply failed', { callId, message: errorMessage(err) }));
|
|
@@ -218,11 +228,13 @@ export class RemoteHarness extends EventEmitter {
|
|
|
218
228
|
const callId = event.callId;
|
|
219
229
|
void bridgeDrive(event, context)
|
|
220
230
|
.then((frame) => {
|
|
221
|
-
if (!closed)
|
|
231
|
+
if (!closed) {
|
|
222
232
|
return duplex.write({ ...frame, callId });
|
|
233
|
+
}
|
|
223
234
|
const stagedPath = frame.payload?.path;
|
|
224
|
-
if (stagedPath)
|
|
235
|
+
if (stagedPath) {
|
|
225
236
|
void fs.promises.unlink(stagedPath).catch(noop);
|
|
237
|
+
}
|
|
226
238
|
}, (err) => {
|
|
227
239
|
if (!closed) {
|
|
228
240
|
duplex.write({
|
|
@@ -239,8 +251,9 @@ export class RemoteHarness extends EventEmitter {
|
|
|
239
251
|
const callId = event.callId;
|
|
240
252
|
void bridgeRag(event, context)
|
|
241
253
|
.then((frame) => {
|
|
242
|
-
if (!closed)
|
|
254
|
+
if (!closed) {
|
|
243
255
|
duplex.write({ ...frame, callId });
|
|
256
|
+
}
|
|
244
257
|
}, (err) => {
|
|
245
258
|
if (!closed) {
|
|
246
259
|
duplex.write({
|
|
@@ -254,39 +267,14 @@ export class RemoteHarness extends EventEmitter {
|
|
|
254
267
|
continue;
|
|
255
268
|
}
|
|
256
269
|
if (event.type === 'question-ask') {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
callId,
|
|
264
|
-
message: 'the host cannot ask questions'
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
continue;
|
|
268
|
-
}
|
|
269
|
-
void Promise.resolve()
|
|
270
|
-
.then(() => askUser({
|
|
271
|
-
question: event.question ?? '',
|
|
272
|
-
...(Array.isArray(event.options)
|
|
273
|
-
? { options: event.options.map(String) }
|
|
274
|
-
: {})
|
|
275
|
-
}))
|
|
276
|
-
.then((answer) => {
|
|
277
|
-
if (!closed) {
|
|
278
|
-
duplex.write({ type: 'question-result', callId, answer: answer ?? '' });
|
|
279
|
-
}
|
|
280
|
-
}, (err) => {
|
|
281
|
-
if (!closed) {
|
|
282
|
-
duplex.write({
|
|
283
|
-
type: 'question-result',
|
|
284
|
-
callId,
|
|
285
|
-
message: errorMessage(err)
|
|
286
|
-
});
|
|
270
|
+
answerQuestion(event, {
|
|
271
|
+
askUser: context.askUser,
|
|
272
|
+
reply: (frame) => {
|
|
273
|
+
if (!closed) {
|
|
274
|
+
duplex.write(frame);
|
|
275
|
+
}
|
|
287
276
|
}
|
|
288
|
-
})
|
|
289
|
-
.catch((err) => hlog('question reply failed', { callId, message: errorMessage(err) }));
|
|
277
|
+
});
|
|
290
278
|
continue;
|
|
291
279
|
}
|
|
292
280
|
if (event.type === 'progress') {
|
|
@@ -294,19 +282,21 @@ export class RemoteHarness extends EventEmitter {
|
|
|
294
282
|
continue;
|
|
295
283
|
}
|
|
296
284
|
const wire = fromWire(event);
|
|
297
|
-
if (wire.type === 'aborted')
|
|
285
|
+
if (wire.type === 'aborted') {
|
|
298
286
|
emittedAborted = true;
|
|
287
|
+
}
|
|
299
288
|
yield wire;
|
|
300
289
|
}
|
|
301
290
|
hlog('client wire ended', { received });
|
|
302
291
|
}
|
|
303
292
|
catch (err) {
|
|
304
293
|
if (context.signal?.aborted) {
|
|
305
|
-
if (!emittedAborted)
|
|
294
|
+
if (!emittedAborted) {
|
|
306
295
|
yield { type: 'aborted' };
|
|
296
|
+
}
|
|
307
297
|
return;
|
|
308
298
|
}
|
|
309
|
-
throw died(`harness died mid-run: ${err
|
|
299
|
+
throw died(`harness died mid-run: ${errorMessage(err)}`);
|
|
310
300
|
}
|
|
311
301
|
finally {
|
|
312
302
|
hlog('client run end', { received, aborted: Boolean(context.signal?.aborted) });
|
|
@@ -315,8 +305,9 @@ export class RemoteHarness extends EventEmitter {
|
|
|
315
305
|
closed = true;
|
|
316
306
|
reclaim();
|
|
317
307
|
}
|
|
318
|
-
if (context.signal?.aborted && !emittedAborted)
|
|
308
|
+
if (context.signal?.aborted && !emittedAborted) {
|
|
319
309
|
yield { type: 'aborted' };
|
|
310
|
+
}
|
|
320
311
|
}
|
|
321
312
|
async *download(context) {
|
|
322
313
|
const { client } = await this._ensure();
|
|
@@ -337,25 +328,28 @@ export class RemoteHarness extends EventEmitter {
|
|
|
337
328
|
context.signal?.addEventListener?.('abort', onAbort, { once: true });
|
|
338
329
|
for await (const event of downloadFrames(stream)) {
|
|
339
330
|
const wire = fromDownloadWire(event);
|
|
340
|
-
if (wire.type === 'aborted')
|
|
331
|
+
if (wire.type === 'aborted') {
|
|
341
332
|
emittedAborted = true;
|
|
333
|
+
}
|
|
342
334
|
yield wire;
|
|
343
335
|
}
|
|
344
336
|
}
|
|
345
337
|
catch (err) {
|
|
346
338
|
if (context.signal?.aborted) {
|
|
347
|
-
if (!emittedAborted)
|
|
339
|
+
if (!emittedAborted) {
|
|
348
340
|
yield { type: 'aborted' };
|
|
341
|
+
}
|
|
349
342
|
return;
|
|
350
343
|
}
|
|
351
|
-
throw died(`harness died mid-download: ${err
|
|
344
|
+
throw died(`harness died mid-download: ${errorMessage(err)}`);
|
|
352
345
|
}
|
|
353
346
|
finally {
|
|
354
347
|
context.signal?.removeEventListener?.('abort', onAbort);
|
|
355
348
|
stream?.destroy();
|
|
356
349
|
}
|
|
357
|
-
if (context.signal?.aborted && !emittedAborted)
|
|
350
|
+
if (context.signal?.aborted && !emittedAborted) {
|
|
358
351
|
yield { type: 'aborted' };
|
|
352
|
+
}
|
|
359
353
|
}
|
|
360
354
|
async embed(context) {
|
|
361
355
|
const { client } = await this._ensure();
|
|
@@ -389,8 +383,9 @@ export class RemoteHarness extends EventEmitter {
|
|
|
389
383
|
const duplex = client.speakStream();
|
|
390
384
|
const pump = (async () => {
|
|
391
385
|
try {
|
|
392
|
-
for await (const fragment of context.text)
|
|
386
|
+
for await (const fragment of context.text) {
|
|
393
387
|
duplex.write({ text: fragment });
|
|
388
|
+
}
|
|
394
389
|
duplex.end();
|
|
395
390
|
}
|
|
396
391
|
catch {
|
|
@@ -399,12 +394,11 @@ export class RemoteHarness extends EventEmitter {
|
|
|
399
394
|
})();
|
|
400
395
|
try {
|
|
401
396
|
for await (const frame of frames(duplex)) {
|
|
402
|
-
|
|
403
|
-
yield { audio: chunk.audio, sampleRate: chunk.sampleRate };
|
|
397
|
+
yield { audio: frame.audio, sampleRate: frame.sampleRate };
|
|
404
398
|
}
|
|
405
399
|
}
|
|
406
400
|
finally {
|
|
407
|
-
await pump.catch(
|
|
401
|
+
await pump.catch(noop);
|
|
408
402
|
}
|
|
409
403
|
}
|
|
410
404
|
async getEmbeddingDevice() {
|
|
@@ -423,6 +417,10 @@ export class RemoteHarness extends EventEmitter {
|
|
|
423
417
|
const { client } = await this._ensure();
|
|
424
418
|
await client.setSkillSettings({ entries });
|
|
425
419
|
}
|
|
420
|
+
async setModelIdleTimeout(ms) {
|
|
421
|
+
const { client } = await this._ensure();
|
|
422
|
+
await client.setModelIdleTimeout({ ms });
|
|
423
|
+
}
|
|
426
424
|
async listManagedSkills() {
|
|
427
425
|
const { client } = await this._ensure();
|
|
428
426
|
const response = await client.listManagedSkills({});
|
|
@@ -462,6 +460,14 @@ export class RemoteHarness extends EventEmitter {
|
|
|
462
460
|
const { client } = await this._ensure();
|
|
463
461
|
await client.setCustomModels({ models: entries });
|
|
464
462
|
}
|
|
463
|
+
async previewModelSource(context) {
|
|
464
|
+
const { client } = await this._ensure();
|
|
465
|
+
const response = await client.previewModelSource({
|
|
466
|
+
src: context.src,
|
|
467
|
+
mmprojSrc: context.mmprojSrc
|
|
468
|
+
});
|
|
469
|
+
return readModelSourcePreview(response);
|
|
470
|
+
}
|
|
465
471
|
async skills(agentId, modelName, options) {
|
|
466
472
|
const { client } = await this._ensure();
|
|
467
473
|
const response = await client.skills({
|
|
@@ -482,7 +488,7 @@ export class RemoteHarness extends EventEmitter {
|
|
|
482
488
|
binary.bin,
|
|
483
489
|
{
|
|
484
490
|
min: minVersion,
|
|
485
|
-
|
|
491
|
+
command: binary.command || undefined
|
|
486
492
|
}
|
|
487
493
|
]
|
|
488
494
|
]
|
|
@@ -496,22 +502,20 @@ export class RemoteHarness extends EventEmitter {
|
|
|
496
502
|
allowList: skill.allowList ?? [],
|
|
497
503
|
platform: skill.platforms ?? [],
|
|
498
504
|
status: parseSkillState(skill.status),
|
|
499
|
-
|
|
505
|
+
requires: skill.requirements
|
|
500
506
|
? {
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
...(Object.keys(binMinVersions).length > 0 ? { binMinVersions } : {})
|
|
507
|
-
}
|
|
507
|
+
bins: binaries.map((binary) => binary.bin),
|
|
508
|
+
credentials: skill.requirements.credentials?.length
|
|
509
|
+
? skill.requirements.credentials
|
|
510
|
+
: undefined,
|
|
511
|
+
binMinVersions: Object.keys(binMinVersions).length > 0 ? binMinVersions : undefined
|
|
508
512
|
}
|
|
509
|
-
:
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
513
|
+
: undefined,
|
|
514
|
+
install,
|
|
515
|
+
setup,
|
|
516
|
+
stub: skill.stub === true ? true : undefined,
|
|
517
|
+
minCapabilityProfile: skill.minCapabilityProfile || undefined,
|
|
518
|
+
emoji: skill.emoji || undefined
|
|
515
519
|
};
|
|
516
520
|
});
|
|
517
521
|
}
|
|
@@ -533,24 +537,25 @@ export class RemoteHarness extends EventEmitter {
|
|
|
533
537
|
const { client } = await this._ensure();
|
|
534
538
|
await abortable(client.warmModel({
|
|
535
539
|
model: context.model,
|
|
536
|
-
|
|
540
|
+
agent: context.agent ? knobs(context.agent) : undefined
|
|
537
541
|
}), context.signal);
|
|
538
542
|
}
|
|
539
543
|
async list(options = {}) {
|
|
540
544
|
const { client } = await this._ensure();
|
|
541
|
-
const response =
|
|
545
|
+
const response = await client.listModels({
|
|
542
546
|
type: options.type,
|
|
543
547
|
cachedOnly: options.cachedOnly,
|
|
544
548
|
fullRegistry: options.fullRegistry
|
|
545
|
-
})
|
|
546
|
-
return (response.models ?? []).map(({ actualSize, ...row }) => ({
|
|
549
|
+
});
|
|
550
|
+
return (response.models ?? []).map(({ actualSize, label, ...row }) => ({
|
|
547
551
|
...row,
|
|
548
|
-
|
|
552
|
+
actualSize: actualSize || undefined,
|
|
553
|
+
label: label || undefined
|
|
549
554
|
}));
|
|
550
555
|
}
|
|
551
556
|
async deleteModel(name) {
|
|
552
557
|
const { client } = await this._ensure();
|
|
553
|
-
const response =
|
|
558
|
+
const response = await client.deleteModel({ name });
|
|
554
559
|
return { name: response.name, removed: response.removed, freedBytes: response.freedBytes };
|
|
555
560
|
}
|
|
556
561
|
async clearKvCache() {
|
|
@@ -563,11 +568,13 @@ export class RemoteHarness extends EventEmitter {
|
|
|
563
568
|
try {
|
|
564
569
|
const { client } = await this._ensure();
|
|
565
570
|
const info = await client.describe({});
|
|
566
|
-
if (info.supportsKvCacheDeletion !== true)
|
|
571
|
+
if (info.supportsKvCacheDeletion !== true) {
|
|
567
572
|
return unsupportedKvCacheDeletion();
|
|
573
|
+
}
|
|
568
574
|
const response = await call(client);
|
|
569
|
-
if (response.status === 'success')
|
|
575
|
+
if (response.status === 'success') {
|
|
570
576
|
return { status: 'success' };
|
|
577
|
+
}
|
|
571
578
|
if (response.status === 'failure') {
|
|
572
579
|
return { status: 'failure', error: response.error ?? 'Harness cache deletion failed' };
|
|
573
580
|
}
|
|
@@ -576,13 +583,13 @@ export class RemoteHarness extends EventEmitter {
|
|
|
576
583
|
catch (error) {
|
|
577
584
|
return {
|
|
578
585
|
status: 'failure',
|
|
579
|
-
error:
|
|
586
|
+
error: errorMessage(error)
|
|
580
587
|
};
|
|
581
588
|
}
|
|
582
589
|
}
|
|
583
590
|
async infraModels(profile) {
|
|
584
591
|
const { client } = await this._ensure();
|
|
585
|
-
const response =
|
|
592
|
+
const response = await client.infraModels({ profile });
|
|
586
593
|
return response.models ?? [];
|
|
587
594
|
}
|
|
588
595
|
async capability() {
|
|
@@ -592,16 +599,14 @@ export class RemoteHarness extends EventEmitter {
|
|
|
592
599
|
return {
|
|
593
600
|
capabilityProfile: response.capabilityProfile,
|
|
594
601
|
recommendedModelName: response.recommendedModelName,
|
|
595
|
-
|
|
602
|
+
memoryBudget: memoryBudget
|
|
596
603
|
? {
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
...(memoryBudget.gpuClass ? { gpuClass: memoryBudget.gpuClass } : {})
|
|
602
|
-
}
|
|
604
|
+
totalBytes: memoryBudget.totalBytes,
|
|
605
|
+
availableBytes: memoryBudget.availableBytes,
|
|
606
|
+
source: memoryBudget.source,
|
|
607
|
+
gpuClass: memoryBudget.gpuClass || undefined
|
|
603
608
|
}
|
|
604
|
-
:
|
|
609
|
+
: undefined
|
|
605
610
|
};
|
|
606
611
|
}
|
|
607
612
|
close() {
|
|
@@ -611,8 +616,9 @@ export class RemoteHarness extends EventEmitter {
|
|
|
611
616
|
async describe() {
|
|
612
617
|
const { client } = await this._ensure();
|
|
613
618
|
const describe = client.describe;
|
|
614
|
-
if (!describe)
|
|
619
|
+
if (!describe) {
|
|
615
620
|
return null;
|
|
621
|
+
}
|
|
616
622
|
const info = await describe.call(client, {});
|
|
617
623
|
return {
|
|
618
624
|
toolNames: info?.toolNames ?? [],
|
|
@@ -623,12 +629,14 @@ export class RemoteHarness extends EventEmitter {
|
|
|
623
629
|
}
|
|
624
630
|
async fetchDiagnostics() {
|
|
625
631
|
const session = this._session;
|
|
626
|
-
if (!session || session.dead)
|
|
632
|
+
if (!session || session.dead) {
|
|
627
633
|
return null;
|
|
634
|
+
}
|
|
628
635
|
const client = session.client;
|
|
629
636
|
const diagnostics = client.diagnostics;
|
|
630
|
-
if (!diagnostics)
|
|
637
|
+
if (!diagnostics) {
|
|
631
638
|
return null;
|
|
639
|
+
}
|
|
632
640
|
const snapshot = await diagnostics.call(client, {});
|
|
633
641
|
const device = snapshot?.device;
|
|
634
642
|
return {
|
|
@@ -637,7 +645,7 @@ export class RemoteHarness extends EventEmitter {
|
|
|
637
645
|
sdkLoaded: snapshot?.sdkLoaded ?? false,
|
|
638
646
|
toolNames: snapshot?.toolNames ?? [],
|
|
639
647
|
skills: snapshot?.skills ?? [],
|
|
640
|
-
|
|
648
|
+
device: device || undefined
|
|
641
649
|
};
|
|
642
650
|
}
|
|
643
651
|
}
|
|
@@ -647,10 +655,11 @@ function parseSkillState(value) {
|
|
|
647
655
|
function errorDetails(err) {
|
|
648
656
|
return { error: errorMessage(err), code: errorCode(err) };
|
|
649
657
|
}
|
|
658
|
+
function isToolCallDisplay(value) {
|
|
659
|
+
return isRecord(value) && typeof value.label === 'string';
|
|
660
|
+
}
|
|
650
661
|
function died(message) {
|
|
651
|
-
|
|
652
|
-
err.code = HARNESS_DIED;
|
|
653
|
-
return err;
|
|
662
|
+
return Object.assign(new Error(message), { code: HARNESS_DIED });
|
|
654
663
|
}
|
|
655
664
|
const noop = () => { };
|
|
656
665
|
function abortable(promise, signal) {
|
|
@@ -691,8 +700,9 @@ function knobs(agent) {
|
|
|
691
700
|
}
|
|
692
701
|
async function bridgeAttach(event, attach) {
|
|
693
702
|
try {
|
|
694
|
-
if (!attach)
|
|
703
|
+
if (!attach) {
|
|
695
704
|
return { type: 'attach-result', message: 'the host cannot persist attachments' };
|
|
705
|
+
}
|
|
696
706
|
const bytes = await fs.promises.readFile(event.path ?? '');
|
|
697
707
|
const record = await attach({
|
|
698
708
|
fileName: event.fileName ?? '',
|
|
@@ -711,11 +721,12 @@ async function bridgeAttach(event, attach) {
|
|
|
711
721
|
};
|
|
712
722
|
}
|
|
713
723
|
catch (err) {
|
|
714
|
-
return { type: 'attach-result', message: err
|
|
724
|
+
return { type: 'attach-result', message: errorMessage(err) };
|
|
715
725
|
}
|
|
716
726
|
finally {
|
|
717
|
-
if (event.path)
|
|
727
|
+
if (event.path) {
|
|
718
728
|
void fs.promises.unlink(event.path).catch(noop);
|
|
729
|
+
}
|
|
719
730
|
}
|
|
720
731
|
}
|
|
721
732
|
async function bridgeFetch(event, context, staged) {
|
|
@@ -726,11 +737,12 @@ async function bridgeFetch(event, context, staged) {
|
|
|
726
737
|
const metaOnly = event.meta === true;
|
|
727
738
|
const found = await context.fetchAttachment({
|
|
728
739
|
attachmentId: event.attachmentId ?? undefined,
|
|
729
|
-
|
|
740
|
+
meta: metaOnly ? true : undefined,
|
|
730
741
|
signal: context.signal
|
|
731
742
|
});
|
|
732
|
-
if (!found)
|
|
743
|
+
if (!found) {
|
|
733
744
|
return { type: 'fetch-result' };
|
|
745
|
+
}
|
|
734
746
|
const size = 'bytes' in found && found.bytes !== null ? found.bytes.byteLength : found.byteLength;
|
|
735
747
|
if (metaOnly) {
|
|
736
748
|
return {
|
|
@@ -757,20 +769,55 @@ async function bridgeFetch(event, context, staged) {
|
|
|
757
769
|
};
|
|
758
770
|
}
|
|
759
771
|
catch (err) {
|
|
760
|
-
return { type: 'fetch-result', message: err
|
|
772
|
+
return { type: 'fetch-result', message: errorMessage(err) };
|
|
761
773
|
}
|
|
762
774
|
}
|
|
775
|
+
const DriveRequestSchema = z.discriminatedUnion('op', [
|
|
776
|
+
z.looseObject({ op: z.literal('entry'), driveKey: z.string(), key: z.string() }),
|
|
777
|
+
z.looseObject({ op: z.literal('get'), driveKey: z.string(), key: z.string() }),
|
|
778
|
+
z.looseObject({ op: z.literal('read'), driveKey: z.string(), key: z.string() }),
|
|
779
|
+
z.looseObject({
|
|
780
|
+
op: z.literal('list'),
|
|
781
|
+
driveKey: z.string(),
|
|
782
|
+
folder: z.string(),
|
|
783
|
+
skip: z.array(z.string()),
|
|
784
|
+
limit: z.number(),
|
|
785
|
+
cursor: z.string().nullable()
|
|
786
|
+
}),
|
|
787
|
+
z.looseObject({
|
|
788
|
+
op: z.literal('write'),
|
|
789
|
+
driveKey: z.string(),
|
|
790
|
+
key: z.string(),
|
|
791
|
+
path: z.string(),
|
|
792
|
+
executable: z.boolean().optional()
|
|
793
|
+
})
|
|
794
|
+
]);
|
|
763
795
|
async function bridgeDrive(event, context) {
|
|
764
|
-
if (!context.driveOp)
|
|
796
|
+
if (!context.driveOp) {
|
|
765
797
|
return { type: 'drive-result', message: 'the host cannot proxy drives' };
|
|
798
|
+
}
|
|
766
799
|
try {
|
|
767
|
-
const payload = await context.driveOp(event.payload);
|
|
800
|
+
const payload = await context.driveOp(DriveRequestSchema.parse(event.payload));
|
|
768
801
|
return { type: 'drive-result', payload };
|
|
769
802
|
}
|
|
770
803
|
catch (err) {
|
|
771
|
-
return { type: 'drive-result', message:
|
|
804
|
+
return { type: 'drive-result', message: errorMessage(err) };
|
|
772
805
|
}
|
|
773
806
|
}
|
|
807
|
+
function answerQuestion(event, { askUser, reply }) {
|
|
808
|
+
const callId = event.callId;
|
|
809
|
+
if (!askUser) {
|
|
810
|
+
reply({ type: 'question-result', callId, message: 'the host cannot ask questions' });
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
void Promise.resolve()
|
|
814
|
+
.then(() => askUser({
|
|
815
|
+
question: event.question ?? '',
|
|
816
|
+
options: Array.isArray(event.options) ? event.options.map(String) : undefined
|
|
817
|
+
}))
|
|
818
|
+
.then((answer) => reply({ type: 'question-result', callId, answer: answer ?? '' }), (err) => reply({ type: 'question-result', callId, message: errorMessage(err) }))
|
|
819
|
+
.catch((err) => hlog('question reply failed', { callId, message: errorMessage(err) }));
|
|
820
|
+
}
|
|
774
821
|
async function bridgeRag(event, context) {
|
|
775
822
|
if (!context.ragSearch) {
|
|
776
823
|
return {
|
|
@@ -786,7 +833,7 @@ async function bridgeRag(event, context) {
|
|
|
786
833
|
return { type: 'rag-result', result };
|
|
787
834
|
}
|
|
788
835
|
catch (err) {
|
|
789
|
-
return { type: 'rag-result', message:
|
|
836
|
+
return { type: 'rag-result', message: errorMessage(err) };
|
|
790
837
|
}
|
|
791
838
|
}
|
|
792
839
|
async function* frames(stream) {
|
|
@@ -807,8 +854,9 @@ async function* frames(stream) {
|
|
|
807
854
|
queue.end();
|
|
808
855
|
});
|
|
809
856
|
yield* queue;
|
|
810
|
-
if (error)
|
|
857
|
+
if (error) {
|
|
811
858
|
throw error;
|
|
859
|
+
}
|
|
812
860
|
}
|
|
813
861
|
async function* downloadFrames(stream) {
|
|
814
862
|
const queue = pushQueue();
|
|
@@ -821,6 +869,7 @@ async function* downloadFrames(stream) {
|
|
|
821
869
|
queue.end();
|
|
822
870
|
});
|
|
823
871
|
yield* queue;
|
|
824
|
-
if (error)
|
|
872
|
+
if (error) {
|
|
825
873
|
throw error;
|
|
874
|
+
}
|
|
826
875
|
}
|