@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
|
@@ -5,8 +5,9 @@ function isTurnBoundary(message) {
|
|
|
5
5
|
}
|
|
6
6
|
export function contextCandidates(history) {
|
|
7
7
|
const { prefix, turns } = splitTurns(history);
|
|
8
|
-
if (!turns.length)
|
|
8
|
+
if (!turns.length) {
|
|
9
9
|
return [{ history, droppedTurns: 0 }];
|
|
10
|
+
}
|
|
10
11
|
const maxDropped = Math.max(0, turns.length - 1);
|
|
11
12
|
const candidates = dropCounts(maxDropped).map((droppedTurns) => ({
|
|
12
13
|
history: droppedTurns ? [...prefix, ...turns.slice(droppedTurns).flat()] : history,
|
|
@@ -17,57 +18,60 @@ export function contextCandidates(history) {
|
|
|
17
18
|
}
|
|
18
19
|
function splitTurns(history) {
|
|
19
20
|
const firstUser = history.findIndex(isTurnBoundary);
|
|
20
|
-
if (firstUser === -1)
|
|
21
|
+
if (firstUser === -1) {
|
|
21
22
|
return { prefix: history, turns: [] };
|
|
23
|
+
}
|
|
22
24
|
const prefix = history.slice(0, firstUser);
|
|
23
25
|
const starts = [];
|
|
24
|
-
for (
|
|
25
|
-
if (isTurnBoundary(
|
|
26
|
+
for (const [i, message] of history.entries()) {
|
|
27
|
+
if (i >= firstUser && isTurnBoundary(message)) {
|
|
26
28
|
starts.push(i);
|
|
29
|
+
}
|
|
27
30
|
}
|
|
28
31
|
const turns = starts.map((start, index) => history.slice(start, starts[index + 1]));
|
|
29
32
|
return { prefix, turns };
|
|
30
33
|
}
|
|
31
34
|
function dropCounts(max) {
|
|
32
35
|
const counts = [0];
|
|
33
|
-
|
|
36
|
+
let last = 0;
|
|
37
|
+
for (let step = 1; last < max; step *= 2) {
|
|
34
38
|
const next = Math.min(max, step);
|
|
35
|
-
if (next
|
|
36
|
-
|
|
39
|
+
if (next === last) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
counts.push(next);
|
|
43
|
+
last = next;
|
|
37
44
|
}
|
|
38
45
|
return counts;
|
|
39
46
|
}
|
|
40
47
|
function appendToolCompactions(candidates) {
|
|
41
48
|
const last = candidates[candidates.length - 1];
|
|
42
|
-
if (!last)
|
|
49
|
+
if (!last) {
|
|
43
50
|
return;
|
|
51
|
+
}
|
|
44
52
|
const tools = compactableTools(last.history);
|
|
45
53
|
let history = last.history;
|
|
46
54
|
while (true) {
|
|
47
55
|
const selected = longestTool(tools);
|
|
48
|
-
if (!selected)
|
|
56
|
+
if (!selected) {
|
|
49
57
|
return;
|
|
58
|
+
}
|
|
50
59
|
selected.target = Math.max(TOOL_RESULT_TRUNCATION_MARKER.length, Math.floor(selected.target / 2));
|
|
51
60
|
history = history.map(compactTool.bind(null, selected));
|
|
52
61
|
candidates.push({ history, droppedTurns: last.droppedTurns });
|
|
53
62
|
}
|
|
54
63
|
}
|
|
55
64
|
function compactableTools(history) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
if (!isTurnBoundary(history[index]))
|
|
59
|
-
continue;
|
|
60
|
-
newestUser = index;
|
|
61
|
-
break;
|
|
62
|
-
}
|
|
63
|
-
if (newestUser === -1)
|
|
65
|
+
const newestUser = history.findLastIndex(isTurnBoundary);
|
|
66
|
+
if (newestUser === -1) {
|
|
64
67
|
return [];
|
|
68
|
+
}
|
|
65
69
|
const tools = [];
|
|
66
|
-
for (
|
|
67
|
-
|
|
68
|
-
|
|
70
|
+
for (const [index, message] of history.entries()) {
|
|
71
|
+
if (index <= newestUser || message.role !== 'tool')
|
|
72
|
+
continue;
|
|
73
|
+
if (message.content.length <= TOOL_RESULT_TRUNCATION_MARKER.length)
|
|
69
74
|
continue;
|
|
70
|
-
}
|
|
71
75
|
tools.push({ index, original: message.content, target: message.content.length });
|
|
72
76
|
}
|
|
73
77
|
return tools;
|
|
@@ -113,6 +113,17 @@ export interface WarmModelContext {
|
|
|
113
113
|
agent?: AgentKnobs;
|
|
114
114
|
signal?: CompletionContext['signal'];
|
|
115
115
|
}
|
|
116
|
+
export type LoadModelContext = WarmModelContext;
|
|
117
|
+
export interface LoadModelResult {
|
|
118
|
+
loaded: boolean;
|
|
119
|
+
reason?: 'memory';
|
|
120
|
+
}
|
|
121
|
+
export interface UnloadModelContext {
|
|
122
|
+
model: string;
|
|
123
|
+
}
|
|
124
|
+
export interface UnloadModelResult {
|
|
125
|
+
unloaded: boolean;
|
|
126
|
+
}
|
|
116
127
|
export interface DownloadContext {
|
|
117
128
|
model: string;
|
|
118
129
|
addon?: string;
|
|
@@ -165,6 +176,24 @@ export interface CapabilityInfo {
|
|
|
165
176
|
recommendedModelName: string;
|
|
166
177
|
memoryBudget?: MemoryBudget;
|
|
167
178
|
}
|
|
179
|
+
export interface CredentialEntry {
|
|
180
|
+
key: string;
|
|
181
|
+
token?: string | null;
|
|
182
|
+
expiresAt?: number | null;
|
|
183
|
+
agentId?: string | null;
|
|
184
|
+
skill?: string | null;
|
|
185
|
+
}
|
|
186
|
+
export interface SkillsOptions {
|
|
187
|
+
readonly refresh?: boolean;
|
|
188
|
+
readonly skipCredentialProbe?: boolean;
|
|
189
|
+
}
|
|
190
|
+
export interface SkillWriteResult {
|
|
191
|
+
ok: boolean;
|
|
192
|
+
}
|
|
193
|
+
export interface InfraModel {
|
|
194
|
+
name: string;
|
|
195
|
+
addon: string;
|
|
196
|
+
}
|
|
168
197
|
export interface HarnessContract {
|
|
169
198
|
completion(context: CompletionContext): AsyncIterable<HarnessEvent>;
|
|
170
199
|
invoke?(context: InvokeContext): AsyncIterable<HarnessEvent>;
|
|
@@ -183,24 +212,16 @@ export interface HarnessContract {
|
|
|
183
212
|
suspend?(): Promise<void> | void;
|
|
184
213
|
wakeup?(): Promise<void> | void;
|
|
185
214
|
resume?(): Promise<void> | void;
|
|
186
|
-
skills?(agentId?: string | null, modelName?: string | null, options?:
|
|
187
|
-
readonly refresh?: boolean;
|
|
188
|
-
readonly skipCredentialProbe?: boolean;
|
|
189
|
-
}): Promise<ResolvedSkillCatalogEntry[]>;
|
|
215
|
+
skills?(agentId?: string | null, modelName?: string | null, options?: SkillsOptions): Promise<ResolvedSkillCatalogEntry[]>;
|
|
190
216
|
tools?(): Promise<ToolCatalogEntry[]>;
|
|
191
|
-
setCredentials?(entries: ReadonlyArray<
|
|
192
|
-
key: string;
|
|
193
|
-
token?: string | null;
|
|
194
|
-
expiresAt?: number | null;
|
|
195
|
-
agentId?: string | null;
|
|
196
|
-
skill?: string | null;
|
|
197
|
-
}>): void | Promise<void>;
|
|
217
|
+
setCredentials?(entries: ReadonlyArray<CredentialEntry>): void | Promise<void>;
|
|
198
218
|
setSkillSettings?(entries: ReadonlyArray<{
|
|
199
219
|
skill: string;
|
|
200
220
|
key: string;
|
|
201
221
|
value: string;
|
|
202
222
|
agentId?: string | null;
|
|
203
223
|
}>): void | Promise<void>;
|
|
224
|
+
setModelIdleTimeout?(ms: number): void | Promise<void>;
|
|
204
225
|
listManagedSkills?(): Promise<ManagedSkill[]>;
|
|
205
226
|
readSkillFile?(name: string): Promise<SkillFileContent | null>;
|
|
206
227
|
writeSkillFile?(name: string, content: string): Promise<{
|
|
@@ -214,13 +235,12 @@ export interface HarnessContract {
|
|
|
214
235
|
}>;
|
|
215
236
|
list?(options?: ListModelsOptions): Promise<ModelInfo[]>;
|
|
216
237
|
warmModel?(context: WarmModelContext): Promise<void>;
|
|
238
|
+
loadModel?(context: LoadModelContext): Promise<LoadModelResult>;
|
|
239
|
+
unloadModel?(context: UnloadModelContext): Promise<UnloadModelResult>;
|
|
217
240
|
deleteModel?(name: string): Promise<DeleteModelSummary>;
|
|
218
241
|
clearKvCache?(): Promise<KvCacheDeletionResult>;
|
|
219
242
|
deleteKvCache?(kvCacheKey: string): Promise<KvCacheDeletionResult>;
|
|
220
|
-
infraModels?(profile: string): Promise<ReadonlyArray<
|
|
221
|
-
name: string;
|
|
222
|
-
addon: string;
|
|
223
|
-
}>>;
|
|
243
|
+
infraModels?(profile: string): Promise<ReadonlyArray<InfraModel>>;
|
|
224
244
|
setCustomModels?(entries: ReadonlyArray<CustomModelEntry>): void | Promise<void>;
|
|
225
245
|
previewModelSource?(context: PreviewModelSourceContext): Promise<ModelSourcePreview>;
|
|
226
246
|
capability?(): Promise<CapabilityInfo>;
|
|
@@ -4,18 +4,18 @@ export declare function diagramRepairPromptCount(content: string, parentRunId?:
|
|
|
4
4
|
export declare function isDiagramRepairPrompt(content: string): boolean;
|
|
5
5
|
export declare function completeMermaidDiagramCount(content: string): number;
|
|
6
6
|
export declare function diagramRepairAccepted(text: string): boolean;
|
|
7
|
-
|
|
7
|
+
interface DiagramRepairRecord {
|
|
8
8
|
readonly id: string;
|
|
9
9
|
readonly seq: number;
|
|
10
10
|
readonly runId?: string | null;
|
|
11
11
|
readonly parentId?: string | null;
|
|
12
|
-
}
|
|
13
|
-
export
|
|
12
|
+
}
|
|
13
|
+
export interface DiagramRepairLink {
|
|
14
14
|
readonly expectedCount: number;
|
|
15
15
|
readonly parentId: string;
|
|
16
16
|
readonly promptId: string;
|
|
17
17
|
readonly promptText: string;
|
|
18
18
|
readonly runId: string;
|
|
19
|
-
}
|
|
19
|
+
}
|
|
20
20
|
export declare function diagramRepairLinks<T extends DiagramRepairRecord>(records: ReadonlyArray<T>, textOf: (record: T) => string | null): ReadonlyArray<DiagramRepairLink>;
|
|
21
21
|
export {};
|
|
@@ -3,8 +3,9 @@ export const DIAGRAM_REPAIR_PROMPT_SUFFIX = 'Rewrite the complete previous answe
|
|
|
3
3
|
'Common fixes: put every label with spaces or punctuation in double quotes like A["Send (HTTP)"]; never use lowercase end as a node label - write "End"; the first line inside the fence must be the diagram type; close the fence before any prose - never leave a sentence inside it; give every node a unique id.';
|
|
4
4
|
export function diagramRepairPromptCount(content, parentRunId) {
|
|
5
5
|
const match = /^<!-- qvac:diagram-repair:(\d+):([^\s>]+) -->\n(\d+) Mermaid diagram(?:s)? in your previous answer fail(?:s)? to render\.\n/.exec(content);
|
|
6
|
-
if (!match || !content.endsWith(`\n\n${DIAGRAM_REPAIR_PROMPT_SUFFIX}`))
|
|
6
|
+
if (!match || !content.endsWith(`\n\n${DIAGRAM_REPAIR_PROMPT_SUFFIX}`)) {
|
|
7
7
|
return null;
|
|
8
|
+
}
|
|
8
9
|
const expected = Number(match[1]);
|
|
9
10
|
return Number.isSafeInteger(expected) &&
|
|
10
11
|
expected > 0 &&
|
|
@@ -31,8 +32,9 @@ export function diagramRepairLinks(records, textOf) {
|
|
|
31
32
|
if (!child.runId || !child.parentId)
|
|
32
33
|
return [];
|
|
33
34
|
const parent = byId.get(child.parentId);
|
|
34
|
-
if (!parent?.runId)
|
|
35
|
+
if (!parent?.runId) {
|
|
35
36
|
return [];
|
|
37
|
+
}
|
|
36
38
|
const prompt = [...ordered]
|
|
37
39
|
.reverse()
|
|
38
40
|
.find((candidate) => candidate.seq > parent.seq &&
|
|
@@ -41,8 +43,9 @@ export function diagramRepairLinks(records, textOf) {
|
|
|
41
43
|
diagramRepairPromptCount(textOf(candidate) ?? '', parent.runId ?? undefined) !== null);
|
|
42
44
|
const promptText = prompt ? textOf(prompt) : null;
|
|
43
45
|
const expectedCount = diagramRepairPromptCount(promptText ?? '', parent.runId);
|
|
44
|
-
if (prompt)
|
|
46
|
+
if (prompt) {
|
|
45
47
|
used.add(prompt.id);
|
|
48
|
+
}
|
|
46
49
|
return prompt && promptText && expectedCount
|
|
47
50
|
? [
|
|
48
51
|
{
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AbortSignal } from 'bare-abort-controller';
|
|
2
2
|
export { closePythonWorker as closeDocxWorker } from '../tools/exec/adapters/python/worker/client.ts';
|
|
3
|
-
export
|
|
3
|
+
export interface DocxExtractOptions {
|
|
4
4
|
readonly signal?: AbortSignal;
|
|
5
|
-
}
|
|
5
|
+
}
|
|
6
|
+
export declare function extractDocxText(bytes: Uint8Array, fileName: string, options?: DocxExtractOptions): Promise<string>;
|
|
@@ -13,8 +13,9 @@ function pickTier(availableBytes) {
|
|
|
13
13
|
return 'xhigh';
|
|
14
14
|
if (availableBytes >= 30 * GIB)
|
|
15
15
|
return 'high';
|
|
16
|
-
if (availableBytes >= 8 * GIB)
|
|
16
|
+
if (availableBytes >= 8 * GIB) {
|
|
17
17
|
return 'mid';
|
|
18
|
+
}
|
|
18
19
|
return 'low';
|
|
19
20
|
}
|
|
20
21
|
function tierProfile(budget) {
|
|
@@ -38,8 +39,9 @@ function recommend(budget) {
|
|
|
38
39
|
async function probeSysfs(reads) {
|
|
39
40
|
for (const path of SYSFS_VRAM_PATHS) {
|
|
40
41
|
const raw = await reads.readFile(path);
|
|
41
|
-
if (!raw)
|
|
42
|
+
if (!raw) {
|
|
42
43
|
continue;
|
|
44
|
+
}
|
|
43
45
|
const bytes = Number.parseInt(raw.trim(), 10);
|
|
44
46
|
if (!Number.isNaN(bytes) && bytes > 0) {
|
|
45
47
|
return { totalBytes: bytes, availableBytes: bytes, source: 'vram' };
|
|
@@ -50,25 +52,31 @@ async function probeSysfs(reads) {
|
|
|
50
52
|
async function probeDesktop(reads) {
|
|
51
53
|
const ram = reads.totalmem();
|
|
52
54
|
const addon = probeWithAddon(await reads.readGpuStats(), ram);
|
|
53
|
-
if (addon && addon.source === 'vram')
|
|
55
|
+
if (addon && addon.source === 'vram') {
|
|
54
56
|
return addon;
|
|
57
|
+
}
|
|
55
58
|
const nvidia = await reads.run('nvidia-smi --query-gpu=memory.total --format=csv,noheader,nounits');
|
|
56
59
|
const nvidiaBudget = nvidia ? parseNvidiaSmiOutput(nvidia) : null;
|
|
57
|
-
if (nvidiaBudget)
|
|
60
|
+
if (nvidiaBudget) {
|
|
58
61
|
return nvidiaBudget;
|
|
62
|
+
}
|
|
59
63
|
const rocm = await reads.run('rocm-smi --showmeminfo vram');
|
|
60
64
|
const rocmBudget = rocm ? parseRocmSmiOutput(rocm) : null;
|
|
61
|
-
if (rocmBudget)
|
|
65
|
+
if (rocmBudget) {
|
|
62
66
|
return rocmBudget;
|
|
67
|
+
}
|
|
63
68
|
const sysfs = await probeSysfs(reads);
|
|
64
|
-
if (sysfs)
|
|
69
|
+
if (sysfs) {
|
|
65
70
|
return sysfs;
|
|
71
|
+
}
|
|
66
72
|
const registry = await reads.run(`powershell -Command "${WINDOWS_REGISTRY_QUERY}"`);
|
|
67
73
|
const registryBudget = registry ? parseWindowsRegistryOutput(registry, ram) : null;
|
|
68
|
-
if (registryBudget)
|
|
74
|
+
if (registryBudget) {
|
|
69
75
|
return registryBudget;
|
|
70
|
-
|
|
76
|
+
}
|
|
77
|
+
if (addon) {
|
|
71
78
|
return addon;
|
|
79
|
+
}
|
|
72
80
|
return { ...sharedRamBudget(ram), source: 'no-gpu' };
|
|
73
81
|
}
|
|
74
82
|
async function isPixel(reads) {
|
|
@@ -77,10 +85,12 @@ async function isPixel(reads) {
|
|
|
77
85
|
}
|
|
78
86
|
async function probeMemoryBudget(reads) {
|
|
79
87
|
const os = reads.platform();
|
|
80
|
-
if (os === 'android' || os === 'ios')
|
|
88
|
+
if (os === 'android' || os === 'ios') {
|
|
81
89
|
return mobileBudget(reads.totalmem(), await isPixel(reads));
|
|
82
|
-
|
|
90
|
+
}
|
|
91
|
+
if (os === 'darwin') {
|
|
83
92
|
return sharedRamBudget(reads.totalmem());
|
|
93
|
+
}
|
|
84
94
|
return probeDesktop(reads);
|
|
85
95
|
}
|
|
86
96
|
function forcedProfile() {
|
|
@@ -19,14 +19,17 @@ const INTEGRATED_GPU = [
|
|
|
19
19
|
];
|
|
20
20
|
const SOFTWARE_GPU = [/llvmpipe/i, /swrast/i, /mesa/i];
|
|
21
21
|
export function classifyGpu(name) {
|
|
22
|
-
for (const re of DISCRETE_GPU)
|
|
22
|
+
for (const re of DISCRETE_GPU) {
|
|
23
23
|
if (re.test(name))
|
|
24
24
|
return 'discrete';
|
|
25
|
-
|
|
25
|
+
}
|
|
26
|
+
for (const re of INTEGRATED_GPU) {
|
|
26
27
|
if (re.test(name))
|
|
27
28
|
return 'integrated';
|
|
28
|
-
|
|
29
|
+
}
|
|
30
|
+
for (const re of SOFTWARE_GPU) {
|
|
29
31
|
if (re.test(name))
|
|
30
32
|
return 'software';
|
|
33
|
+
}
|
|
31
34
|
return 'integrated';
|
|
32
35
|
}
|
|
@@ -12,8 +12,9 @@ const StatsSchema = z.object({
|
|
|
12
12
|
function classifyBestDevice(devices, systemRamBytes) {
|
|
13
13
|
for (const device of devices) {
|
|
14
14
|
const cls = classifyGpu(device.name);
|
|
15
|
-
if (cls === 'software')
|
|
15
|
+
if (cls === 'software') {
|
|
16
16
|
continue;
|
|
17
|
+
}
|
|
17
18
|
if (cls === 'discrete') {
|
|
18
19
|
const vram = device.videoMemoryBytes;
|
|
19
20
|
if (vram > systemRamBytes * IGPU_LIE_THRESHOLD) {
|
|
@@ -26,15 +27,18 @@ function classifyBestDevice(devices, systemRamBytes) {
|
|
|
26
27
|
}
|
|
27
28
|
export function probeWithAddon(rawStats, systemRamBytes) {
|
|
28
29
|
const parsed = StatsSchema.safeParse(rawStats);
|
|
29
|
-
if (!parsed.success)
|
|
30
|
+
if (!parsed.success) {
|
|
30
31
|
return null;
|
|
32
|
+
}
|
|
31
33
|
const devices = parsed.data.gpu?.devices ?? [];
|
|
32
|
-
if (devices.length === 0)
|
|
34
|
+
if (devices.length === 0) {
|
|
33
35
|
return null;
|
|
36
|
+
}
|
|
34
37
|
const totalRamBytes = parsed.data.memory?.totalBytes ?? systemRamBytes;
|
|
35
38
|
const best = classifyBestDevice(devices, totalRamBytes);
|
|
36
|
-
if (best)
|
|
39
|
+
if (best) {
|
|
37
40
|
return best;
|
|
41
|
+
}
|
|
38
42
|
if (devices.every((device) => classifyGpu(device.name) === 'software')) {
|
|
39
43
|
return { ...sharedRamBudget(totalRamBytes), source: 'software' };
|
|
40
44
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import b4a from 'b4a';
|
|
1
2
|
import { spawn } from 'child_process';
|
|
2
3
|
import os from 'os';
|
|
3
4
|
import { readSystemStats } from '#hw-gpu-stats';
|
|
@@ -11,8 +12,9 @@ export function runGpuProbeIfRequested() {
|
|
|
11
12
|
}
|
|
12
13
|
export function parseGpuProbeOutput(output) {
|
|
13
14
|
const line = output.trim().split('\n').at(-1) ?? '';
|
|
14
|
-
if (line.length === 0)
|
|
15
|
+
if (line.length === 0) {
|
|
15
16
|
return null;
|
|
17
|
+
}
|
|
16
18
|
try {
|
|
17
19
|
const parsed = JSON.parse(line);
|
|
18
20
|
return typeof parsed === 'object' ? parsed : null;
|
|
@@ -32,7 +34,7 @@ export function spawnGpuProbe(entry = Bare.argv[1]) {
|
|
|
32
34
|
resolve({ ok: false, stats: null });
|
|
33
35
|
}, TIMEOUT_MS);
|
|
34
36
|
child.stdout?.on('data', (chunk) => {
|
|
35
|
-
output +=
|
|
37
|
+
output += b4a.toString(chunk);
|
|
36
38
|
});
|
|
37
39
|
child.stderr?.on('data', () => { });
|
|
38
40
|
child.on('error', () => {
|
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
const os = require('os')
|
|
2
2
|
|
|
3
|
-
//
|
|
4
|
-
// second LLVM) into whichever process imports it
|
|
3
|
+
// lazy: the addon drags the graphics stack (and on Linux a second LLVM) into its importer
|
|
5
4
|
let GPUInfo
|
|
6
5
|
|
|
7
|
-
//
|
|
8
|
-
// device's name and VRAM total, plus system RAM to catch integrated-GPU lies.
|
|
6
|
+
// system RAM is here to catch integrated-GPU lies
|
|
9
7
|
exports.readSystemStats = function readSystemStats() {
|
|
10
8
|
try {
|
|
11
9
|
GPUInfo ??= require('bare-gpu-info')
|
|
12
10
|
const info = new GPUInfo()
|
|
13
11
|
try {
|
|
14
|
-
const devices = []
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
const devices = [...info]
|
|
13
|
+
.filter((gpu) => typeof gpu.memory === 'number' && gpu.name)
|
|
14
|
+
.map((gpu) => ({ name: gpu.name, videoMemoryBytes: gpu.memory }))
|
|
15
|
+
if (devices.length === 0) {
|
|
16
|
+
return null
|
|
18
17
|
}
|
|
19
|
-
|
|
18
|
+
|
|
20
19
|
return { memory: { totalBytes: os.totalmem() }, gpu: { devices } }
|
|
21
20
|
} finally {
|
|
22
21
|
info.destroy()
|
|
@@ -7,25 +7,29 @@ export const IGPU_LIE_THRESHOLD = 0.9;
|
|
|
7
7
|
export function parseNvidiaSmiOutput(stdout) {
|
|
8
8
|
const firstLine = stdout.split('\n')[0] ?? '';
|
|
9
9
|
const mib = Number.parseInt(firstLine, 10);
|
|
10
|
-
if (Number.isNaN(mib) || mib <= 0)
|
|
10
|
+
if (Number.isNaN(mib) || mib <= 0) {
|
|
11
11
|
return null;
|
|
12
|
+
}
|
|
12
13
|
const bytes = mib * 1024 * 1024;
|
|
13
14
|
return { totalBytes: bytes, availableBytes: bytes, source: 'vram', gpuClass: 'discrete' };
|
|
14
15
|
}
|
|
15
16
|
export function parseRocmSmiOutput(stdout) {
|
|
16
17
|
const match = /Total.*?:\s*(\d+)/i.exec(stdout);
|
|
17
|
-
if (!match)
|
|
18
|
+
if (!match) {
|
|
18
19
|
return null;
|
|
20
|
+
}
|
|
19
21
|
const bytes = Number.parseInt(match[1] ?? '', 10);
|
|
20
|
-
if (Number.isNaN(bytes) || bytes <= 0)
|
|
22
|
+
if (Number.isNaN(bytes) || bytes <= 0) {
|
|
21
23
|
return null;
|
|
24
|
+
}
|
|
22
25
|
return { totalBytes: bytes, availableBytes: bytes, source: 'vram' };
|
|
23
26
|
}
|
|
24
27
|
export function parseWindowsRegistryOutput(stdout, systemRamBytes) {
|
|
25
28
|
const firstLine = stdout.split('\n')[0] ?? '';
|
|
26
29
|
const bytes = Number.parseInt(firstLine, 10);
|
|
27
|
-
if (Number.isNaN(bytes) || bytes <= 0)
|
|
30
|
+
if (Number.isNaN(bytes) || bytes <= 0) {
|
|
28
31
|
return null;
|
|
32
|
+
}
|
|
29
33
|
if (bytes > systemRamBytes * IGPU_LIE_THRESHOLD) {
|
|
30
34
|
return { ...sharedRamBudget(systemRamBytes), source: 'integrated' };
|
|
31
35
|
}
|
|
@@ -7,14 +7,16 @@ export async function* bufferBurst(tokens, ms) {
|
|
|
7
7
|
continue;
|
|
8
8
|
}
|
|
9
9
|
if (Date.now() >= deadline) {
|
|
10
|
-
if (burst)
|
|
10
|
+
if (burst) {
|
|
11
11
|
yield burst;
|
|
12
|
+
}
|
|
12
13
|
burst = null;
|
|
13
14
|
yield token;
|
|
14
15
|
continue;
|
|
15
16
|
}
|
|
16
17
|
burst += token;
|
|
17
18
|
}
|
|
18
|
-
if (burst)
|
|
19
|
+
if (burst) {
|
|
19
20
|
yield burst;
|
|
21
|
+
}
|
|
20
22
|
}
|
|
@@ -19,14 +19,16 @@ export async function* stopAtControlToken(tokens, onStop) {
|
|
|
19
19
|
const safe = scanner({ stop: STOP_MARKERS });
|
|
20
20
|
for await (const token of tokens) {
|
|
21
21
|
const shown = safe.push(token);
|
|
22
|
-
if (shown)
|
|
22
|
+
if (shown) {
|
|
23
23
|
yield shown;
|
|
24
|
+
}
|
|
24
25
|
if (safe.stopped !== null) {
|
|
25
26
|
onStop?.(safe.stopped);
|
|
26
27
|
return;
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
const rest = safe.flush();
|
|
30
|
-
if (rest)
|
|
31
|
+
if (rest) {
|
|
31
32
|
yield rest;
|
|
33
|
+
}
|
|
32
34
|
}
|
|
@@ -30,8 +30,9 @@ export function createJoinGuard(markers) {
|
|
|
30
30
|
function mend(text, at, markers) {
|
|
31
31
|
for (;;) {
|
|
32
32
|
const found = spanning(text, at, markers);
|
|
33
|
-
if (found === null)
|
|
33
|
+
if (found === null) {
|
|
34
34
|
return { text, at };
|
|
35
|
+
}
|
|
35
36
|
text = text.slice(0, found.index) + text.slice(found.index + found.marker.length);
|
|
36
37
|
at = found.index;
|
|
37
38
|
}
|
|
@@ -39,8 +40,9 @@ function mend(text, at, markers) {
|
|
|
39
40
|
function spanning(text, at, markers) {
|
|
40
41
|
for (const marker of markers) {
|
|
41
42
|
const index = text.indexOf(marker, Math.max(0, at - marker.length + 1));
|
|
42
|
-
if (index !== -1 && index < at)
|
|
43
|
+
if (index !== -1 && index < at) {
|
|
43
44
|
return { index, marker };
|
|
45
|
+
}
|
|
44
46
|
}
|
|
45
47
|
return null;
|
|
46
48
|
}
|
|
@@ -5,8 +5,9 @@ export function createLoadStall(ms, message) {
|
|
|
5
5
|
rejectStall = reject;
|
|
6
6
|
});
|
|
7
7
|
const arm = () => {
|
|
8
|
-
if (timer !== null)
|
|
8
|
+
if (timer !== null) {
|
|
9
9
|
clearTimeout(timer);
|
|
10
|
+
}
|
|
10
11
|
timer = setTimeout(() => {
|
|
11
12
|
rejectStall?.(new Error(message));
|
|
12
13
|
}, ms);
|
|
@@ -15,8 +16,9 @@ export function createLoadStall(ms, message) {
|
|
|
15
16
|
return {
|
|
16
17
|
bump: arm,
|
|
17
18
|
clear: () => {
|
|
18
|
-
if (timer !== null)
|
|
19
|
+
if (timer !== null) {
|
|
19
20
|
clearTimeout(timer);
|
|
21
|
+
}
|
|
20
22
|
timer = null;
|
|
21
23
|
},
|
|
22
24
|
promise
|
|
@@ -22,8 +22,9 @@ export function createMarkupStreamFilter() {
|
|
|
22
22
|
for (;;) {
|
|
23
23
|
const step = state.closer ? consumeSuppressed(state) : emitUntilOpener(state);
|
|
24
24
|
out += step.out;
|
|
25
|
-
if (step.done)
|
|
25
|
+
if (step.done) {
|
|
26
26
|
return out;
|
|
27
|
+
}
|
|
27
28
|
}
|
|
28
29
|
},
|
|
29
30
|
flush() {
|
|
@@ -52,8 +53,9 @@ function dropResumeNewline(state) {
|
|
|
52
53
|
if (!state.stripNewline || state.buffer.length === 0)
|
|
53
54
|
return;
|
|
54
55
|
state.stripNewline = false;
|
|
55
|
-
if (state.buffer[0] === '\n')
|
|
56
|
+
if (state.buffer[0] === '\n') {
|
|
56
57
|
state.buffer = state.buffer.slice(1);
|
|
58
|
+
}
|
|
57
59
|
}
|
|
58
60
|
function emitUntilOpener(state) {
|
|
59
61
|
dropResumeNewline(state);
|
|
@@ -63,8 +65,9 @@ function emitUntilOpener(state) {
|
|
|
63
65
|
state.guard.cut();
|
|
64
66
|
state.buffer = state.buffer.slice(marker.index + marker.marker.length);
|
|
65
67
|
const closer = MARKUP_CLOSERS[marker.marker];
|
|
66
|
-
if (closer === undefined)
|
|
68
|
+
if (closer === undefined) {
|
|
67
69
|
state.stripNewline = true;
|
|
70
|
+
}
|
|
68
71
|
state.closer = closer ?? null;
|
|
69
72
|
return { out, done: false };
|
|
70
73
|
}
|
|
@@ -8,8 +8,9 @@ export class AbortedError extends Error {
|
|
|
8
8
|
export function raceAbort(promise, signal) {
|
|
9
9
|
if (!signal)
|
|
10
10
|
return promise;
|
|
11
|
-
if (signal.aborted)
|
|
11
|
+
if (signal.aborted) {
|
|
12
12
|
return Promise.reject(new AbortedError());
|
|
13
|
+
}
|
|
13
14
|
return new Promise((resolve, reject) => {
|
|
14
15
|
const onAbort = () => reject(new AbortedError());
|
|
15
16
|
signal.addEventListener('abort', onAbort, { once: true });
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export async function raceTimeout(pending, { ms, fallback }) {
|
|
2
|
+
let timer = null;
|
|
3
|
+
const expired = new Promise((resolve) => {
|
|
4
|
+
timer = setTimeout(() => resolve(fallback), ms);
|
|
5
|
+
});
|
|
6
|
+
try {
|
|
7
|
+
return await Promise.race([pending, expired]);
|
|
8
|
+
}
|
|
9
|
+
finally {
|
|
10
|
+
if (timer !== null) {
|
|
11
|
+
clearTimeout(timer);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|