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