@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
|
@@ -9,6 +9,10 @@ export interface RunOutcomeFacts {
|
|
|
9
9
|
readonly latestFailure: string | null;
|
|
10
10
|
readonly confirmedWrites: ReadonlyArray<string>;
|
|
11
11
|
}
|
|
12
|
+
export interface HistoryTurn {
|
|
13
|
+
readonly role: string;
|
|
14
|
+
readonly content: string;
|
|
15
|
+
}
|
|
12
16
|
export interface RunOutcomeTracker {
|
|
13
17
|
readonly confirmedWrites: string[];
|
|
14
18
|
beginRound(): void;
|
|
@@ -20,14 +24,8 @@ export interface RunOutcomeTracker {
|
|
|
20
24
|
export declare function createRunOutcomeTracker(): RunOutcomeTracker;
|
|
21
25
|
export declare function normalizeToolExecutionOutcome(result: unknown, outcome: ToolExecutionOutcome): ToolExecutionOutcome;
|
|
22
26
|
export declare function failureFromToolExecution(result: unknown, outcome: ToolExecutionOutcome): string | null;
|
|
23
|
-
export declare function degenerateAnswer(outcome: Exclude<RunOutcome, 'answered'>, history: ReadonlyArray<
|
|
24
|
-
|
|
25
|
-
content: string;
|
|
26
|
-
}>, facts?: RunOutcomeFacts): string;
|
|
27
|
-
export declare function lastFailedToolAnswer(history: ReadonlyArray<{
|
|
28
|
-
role: string;
|
|
29
|
-
content: string;
|
|
30
|
-
}>): string | null;
|
|
27
|
+
export declare function degenerateAnswer(outcome: Exclude<RunOutcome, 'answered'>, history: ReadonlyArray<HistoryTurn>, facts?: RunOutcomeFacts): string;
|
|
28
|
+
export declare function lastFailedToolAnswer(history: ReadonlyArray<HistoryTurn>): string | null;
|
|
31
29
|
export declare function writeResult(output: unknown): string | null;
|
|
32
30
|
export declare function unnamedWrites(answer: string, landed: ReadonlyArray<string>): ReadonlyArray<string>;
|
|
33
31
|
export declare function writeReport(landed: ReadonlyArray<string>): string | null;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { TOOL_CONTINUATION_NUDGE } from '../capabilities/tool-turns.js';
|
|
2
|
+
import { isRecord } from '../guards.js';
|
|
2
3
|
export const DEGENERATE_ANSWER_FALLBACK = "I couldn't complete that step and don't have a useful result to share.";
|
|
3
4
|
export const ROUND_CAP_ANSWER = "I ran out of steps before I could finish that. Ask me to continue and I'll pick up where I left off.";
|
|
4
5
|
export const SEARCH_CAPPED_ANSWER = "I searched the web but couldn't find the answer in the results I got.";
|
|
@@ -26,8 +27,9 @@ export function createRunOutcomeTracker() {
|
|
|
26
27
|
record(result, outcome) {
|
|
27
28
|
hasRoundResult = true;
|
|
28
29
|
const failure = failureFromToolExecution(result, outcome);
|
|
29
|
-
if (failure)
|
|
30
|
+
if (failure) {
|
|
30
31
|
roundFailure = failure;
|
|
32
|
+
}
|
|
31
33
|
},
|
|
32
34
|
finishRound() {
|
|
33
35
|
if (!hasRoundResult)
|
|
@@ -36,8 +38,9 @@ export function createRunOutcomeTracker() {
|
|
|
36
38
|
},
|
|
37
39
|
confirmWrite(result) {
|
|
38
40
|
const write = writeResult(result);
|
|
39
|
-
if (write)
|
|
41
|
+
if (write) {
|
|
40
42
|
confirmedWrites.push(write);
|
|
43
|
+
}
|
|
41
44
|
},
|
|
42
45
|
facts() {
|
|
43
46
|
return { latestFailure, confirmedWrites };
|
|
@@ -62,13 +65,15 @@ export function failureFromToolExecution(result, outcome) {
|
|
|
62
65
|
export function degenerateAnswer(outcome, history, facts) {
|
|
63
66
|
const rest = (facts ? facts.latestFailure : lastFailedToolAnswer(history)) ?? cappedAnswer(outcome, history);
|
|
64
67
|
const written = writeReport(facts?.confirmedWrites ?? []);
|
|
65
|
-
if (written)
|
|
68
|
+
if (written) {
|
|
66
69
|
return rest ? `${written}\n\n${rest}` : written;
|
|
70
|
+
}
|
|
67
71
|
return rest ?? DEGENERATE_ANSWER_FALLBACK;
|
|
68
72
|
}
|
|
69
73
|
function cappedAnswer(outcome, history) {
|
|
70
|
-
if (outcome === 'search-capped')
|
|
74
|
+
if (outcome === 'search-capped') {
|
|
71
75
|
return searchCappedAnswer(history);
|
|
76
|
+
}
|
|
72
77
|
if (outcome === 'time-capped')
|
|
73
78
|
return TIME_CAPPED_ANSWER;
|
|
74
79
|
return outcome === 'exhausted' ? ROUND_CAP_ANSWER : null;
|
|
@@ -90,33 +95,40 @@ function searchCappedAnswer(history) {
|
|
|
90
95
|
continue;
|
|
91
96
|
seen.add(url);
|
|
92
97
|
lines.push(`- ${title.trim()}: ${url}`);
|
|
93
|
-
if (lines.length === MAX_CAPPED_SOURCES)
|
|
98
|
+
if (lines.length === MAX_CAPPED_SOURCES) {
|
|
94
99
|
break;
|
|
100
|
+
}
|
|
95
101
|
}
|
|
96
102
|
}
|
|
97
|
-
if (!lines.length)
|
|
103
|
+
if (!lines.length) {
|
|
98
104
|
return SEARCH_CAPPED_ANSWER;
|
|
105
|
+
}
|
|
99
106
|
return `${SEARCH_CAPPED_ANSWER} These pages looked most relevant:\n${lines.join('\n')}`;
|
|
100
107
|
}
|
|
101
108
|
export function lastFailedToolAnswer(history) {
|
|
102
109
|
for (let i = history.length - 1; i >= 0; i--) {
|
|
103
110
|
const turn = history[i];
|
|
104
|
-
if (turn?.role === 'user' && turn.content === TOOL_CONTINUATION_NUDGE)
|
|
111
|
+
if (turn?.role === 'user' && turn.content === TOOL_CONTINUATION_NUDGE) {
|
|
105
112
|
continue;
|
|
106
|
-
|
|
113
|
+
}
|
|
114
|
+
if (turn?.role !== 'tool') {
|
|
107
115
|
return null;
|
|
116
|
+
}
|
|
108
117
|
const failure = failureText(turn.content.replace(TOOL_RESULT_HEADER_RE, ''));
|
|
109
|
-
if (failure)
|
|
118
|
+
if (failure) {
|
|
110
119
|
return failure;
|
|
120
|
+
}
|
|
111
121
|
}
|
|
112
122
|
return null;
|
|
113
123
|
}
|
|
114
124
|
export function writeResult(output) {
|
|
115
125
|
const result = asRecord(output);
|
|
116
|
-
if (!result || typeof result.status !== 'number')
|
|
126
|
+
if (!result || typeof result.status !== 'number') {
|
|
117
127
|
return null;
|
|
118
|
-
|
|
128
|
+
}
|
|
129
|
+
if (result.status >= 400 || nonEmpty(result.error)) {
|
|
119
130
|
return null;
|
|
131
|
+
}
|
|
120
132
|
return nonEmpty(result.body);
|
|
121
133
|
}
|
|
122
134
|
export function unnamedWrites(answer, landed) {
|
|
@@ -139,8 +151,9 @@ export function writeReport(landed) {
|
|
|
139
151
|
const share = Math.floor(MAX_SUCCESS_CHARS / listed.length);
|
|
140
152
|
const lines = listed.map((write) => bound(write, share));
|
|
141
153
|
const dropped = landed.length - listed.length;
|
|
142
|
-
if (dropped)
|
|
154
|
+
if (dropped) {
|
|
143
155
|
lines.push(`(+${dropped} more)`);
|
|
156
|
+
}
|
|
144
157
|
return `${WRITE_RESULT_LEAD}\n${lines.join('\n')}`;
|
|
145
158
|
}
|
|
146
159
|
function failureText(payload) {
|
|
@@ -149,17 +162,21 @@ function failureText(payload) {
|
|
|
149
162
|
}
|
|
150
163
|
function resultFailure(value) {
|
|
151
164
|
const result = typeof value === 'string' ? parsed(value) : asRecord(value);
|
|
152
|
-
if (!result)
|
|
165
|
+
if (!result) {
|
|
153
166
|
return null;
|
|
154
|
-
|
|
167
|
+
}
|
|
168
|
+
if (result.denied === true || result.guidance === true) {
|
|
155
169
|
return null;
|
|
170
|
+
}
|
|
156
171
|
const status = typeof result.status === 'number' ? result.status : null;
|
|
157
172
|
const httpSuffix = status !== null && status >= 400 ? ` (HTTP ${status.toString()})` : '';
|
|
158
173
|
const error = nonEmpty(result.error);
|
|
159
|
-
if (error)
|
|
174
|
+
if (error) {
|
|
160
175
|
return `${bound(error, MAX_FAILURE_CHARS)}${httpSuffix}`;
|
|
161
|
-
|
|
176
|
+
}
|
|
177
|
+
if (status !== null && status >= 400) {
|
|
162
178
|
return httpFailure(status, result.body);
|
|
179
|
+
}
|
|
163
180
|
if (typeof result.exitCode === 'number' && result.exitCode !== 0) {
|
|
164
181
|
const output = nonEmpty(result.stderr) ?? nonEmpty(result.stdout);
|
|
165
182
|
return output ? bound(output, MAX_FAILURE_CHARS) : null;
|
|
@@ -174,8 +191,9 @@ function httpFailure(status, body) {
|
|
|
174
191
|
}
|
|
175
192
|
function apiMessage(body) {
|
|
176
193
|
const value = typeof body === 'string' ? parsed(body) : asRecord(body);
|
|
177
|
-
if (!value)
|
|
194
|
+
if (!value) {
|
|
178
195
|
return null;
|
|
196
|
+
}
|
|
179
197
|
const error = value.error;
|
|
180
198
|
const fromError = typeof error === 'string' ? nonEmpty(error) : nonEmpty(asRecord(error)?.['message']);
|
|
181
199
|
return fromError ?? nonEmpty(value.message);
|
|
@@ -189,9 +207,7 @@ function parsed(payload) {
|
|
|
189
207
|
}
|
|
190
208
|
}
|
|
191
209
|
function asRecord(value) {
|
|
192
|
-
return value &&
|
|
193
|
-
? value
|
|
194
|
-
: null;
|
|
210
|
+
return isRecord(value) && !Array.isArray(value) ? value : null;
|
|
195
211
|
}
|
|
196
212
|
function nonEmpty(value) {
|
|
197
213
|
if (typeof value !== 'string')
|
|
@@ -5,8 +5,9 @@ export function withHomebrewPath(path, platformName) {
|
|
|
5
5
|
const dirs = (path ?? '').split(':').filter(Boolean);
|
|
6
6
|
const seen = new Set(dirs);
|
|
7
7
|
const missing = HOMEBREW_BIN_DIRS.filter((dir) => !seen.has(dir));
|
|
8
|
-
if (missing.length === 0)
|
|
8
|
+
if (missing.length === 0) {
|
|
9
9
|
return path;
|
|
10
|
+
}
|
|
10
11
|
return [...dirs, ...missing].join(':');
|
|
11
12
|
}
|
|
12
13
|
export const EXEC_ENV_ALLOWLIST = [
|
|
@@ -44,12 +45,14 @@ export function execEnv(env, platformName) {
|
|
|
44
45
|
const keys = [...EXEC_ENV_ALLOWLIST, ...(PLATFORM_EXEC_ENV_ALLOWLIST[platformName] ?? [])];
|
|
45
46
|
for (const key of keys) {
|
|
46
47
|
const value = env[key];
|
|
47
|
-
if (value !== undefined)
|
|
48
|
+
if (value !== undefined) {
|
|
48
49
|
out[key] = value;
|
|
50
|
+
}
|
|
49
51
|
}
|
|
50
52
|
const path = withHomebrewPath(out.PATH ?? env.Path, platformName);
|
|
51
|
-
if (path !== undefined)
|
|
53
|
+
if (path !== undefined) {
|
|
52
54
|
out.PATH = path;
|
|
55
|
+
}
|
|
53
56
|
return out;
|
|
54
57
|
}
|
|
55
58
|
export function spawnEnv(env, platformName, overrides) {
|
|
@@ -10,23 +10,26 @@ export class TextCoalescer {
|
|
|
10
10
|
this._holdMs = holdMs;
|
|
11
11
|
}
|
|
12
12
|
async add(type, text) {
|
|
13
|
-
if (this._buffered && this._buffered.type !== type)
|
|
13
|
+
if (this._buffered && this._buffered.type !== type) {
|
|
14
14
|
await this.flush();
|
|
15
|
+
}
|
|
15
16
|
if (!this._buffered) {
|
|
16
17
|
this._buffered = { type, text: '' };
|
|
17
18
|
this._hold = setTimeout(() => void this.flush(), this._holdMs);
|
|
18
19
|
}
|
|
19
20
|
this._buffered.text += text;
|
|
20
|
-
if (this._buffered.text.length >= this._cap)
|
|
21
|
+
if (this._buffered.text.length >= this._cap) {
|
|
21
22
|
await this.flush();
|
|
23
|
+
}
|
|
22
24
|
}
|
|
23
25
|
flush() {
|
|
24
26
|
if (this._hold) {
|
|
25
27
|
clearTimeout(this._hold);
|
|
26
28
|
this._hold = null;
|
|
27
29
|
}
|
|
28
|
-
if (!this._buffered)
|
|
30
|
+
if (!this._buffered) {
|
|
29
31
|
return Promise.resolve();
|
|
32
|
+
}
|
|
30
33
|
const { type, text } = this._buffered;
|
|
31
34
|
this._buffered = null;
|
|
32
35
|
return this._write(type, text);
|
|
@@ -10,6 +10,20 @@ function findEarliest(buffer, tags) {
|
|
|
10
10
|
const found = firstMarker(buffer, tags);
|
|
11
11
|
return found === null ? null : { idx: found.index, len: found.marker.length };
|
|
12
12
|
}
|
|
13
|
+
function nextTag(buffer, inThink) {
|
|
14
|
+
const open = findEarliest(buffer, OPEN_TAGS);
|
|
15
|
+
const close = findEarliest(buffer, CLOSE_TAGS);
|
|
16
|
+
if (inThink) {
|
|
17
|
+
if (open && (!close || open.idx < close.idx)) {
|
|
18
|
+
return { ...open, inThink: true };
|
|
19
|
+
}
|
|
20
|
+
return close && { ...close, inThink: false };
|
|
21
|
+
}
|
|
22
|
+
if (close && (!open || close.idx < open.idx)) {
|
|
23
|
+
return { ...close, inThink: false };
|
|
24
|
+
}
|
|
25
|
+
return open && { ...open, inThink: true };
|
|
26
|
+
}
|
|
13
27
|
export async function* splitThinking(tokens, opts) {
|
|
14
28
|
let buffer = '';
|
|
15
29
|
let inThink = opts?.startInThink === true;
|
|
@@ -20,75 +34,54 @@ export async function* splitThinking(tokens, opts) {
|
|
|
20
34
|
};
|
|
21
35
|
const emit = (type, text) => {
|
|
22
36
|
const shown = guards[type].push(text);
|
|
23
|
-
if (!shown)
|
|
37
|
+
if (!shown) {
|
|
24
38
|
return null;
|
|
25
|
-
|
|
39
|
+
}
|
|
40
|
+
if (type === 'thinking' && unproven !== null) {
|
|
26
41
|
unproven += shown;
|
|
42
|
+
}
|
|
27
43
|
return { type, text: shown };
|
|
28
44
|
};
|
|
29
45
|
for await (const token of tokens) {
|
|
30
46
|
buffer += token;
|
|
31
47
|
while (true) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if (open && (!close || open.idx < close.idx)) {
|
|
36
|
-
const event = emit('thinking', buffer.slice(0, open.idx));
|
|
37
|
-
if (event)
|
|
38
|
-
yield event;
|
|
39
|
-
guards.thinking.cut();
|
|
40
|
-
buffer = buffer.slice(open.idx + open.len);
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
if (!close)
|
|
44
|
-
break;
|
|
45
|
-
const event = emit('thinking', buffer.slice(0, close.idx));
|
|
46
|
-
if (event)
|
|
47
|
-
yield event;
|
|
48
|
-
guards.thinking.cut();
|
|
49
|
-
buffer = buffer.slice(close.idx + close.len);
|
|
50
|
-
inThink = false;
|
|
51
|
-
unproven = null;
|
|
52
|
-
continue;
|
|
48
|
+
const tag = nextTag(buffer, inThink);
|
|
49
|
+
if (!tag) {
|
|
50
|
+
break;
|
|
53
51
|
}
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
-
if (
|
|
57
|
-
|
|
58
|
-
if (event)
|
|
59
|
-
yield event;
|
|
60
|
-
guards.content.cut();
|
|
61
|
-
buffer = buffer.slice(close.idx + close.len);
|
|
62
|
-
continue;
|
|
52
|
+
const type = inThink ? 'thinking' : 'content';
|
|
53
|
+
const event = emit(type, buffer.slice(0, tag.idx));
|
|
54
|
+
if (event) {
|
|
55
|
+
yield event;
|
|
63
56
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
guards.content.cut();
|
|
69
|
-
buffer = buffer.slice(open.idx + open.len);
|
|
70
|
-
inThink = true;
|
|
71
|
-
continue;
|
|
57
|
+
guards[type].cut();
|
|
58
|
+
buffer = buffer.slice(tag.idx + tag.len);
|
|
59
|
+
if (inThink && !tag.inThink) {
|
|
60
|
+
unproven = null;
|
|
72
61
|
}
|
|
73
|
-
|
|
62
|
+
inThink = tag.inThink;
|
|
74
63
|
}
|
|
75
64
|
const held = holdback(buffer, inThink ? CLOSE_TAGS : ALL_TAGS);
|
|
76
65
|
if (buffer.length > held) {
|
|
77
66
|
const event = emit(inThink ? 'thinking' : 'content', buffer.slice(0, buffer.length - held));
|
|
78
|
-
if (event)
|
|
67
|
+
if (event) {
|
|
79
68
|
yield event;
|
|
69
|
+
}
|
|
80
70
|
buffer = buffer.slice(buffer.length - held);
|
|
81
71
|
}
|
|
82
72
|
}
|
|
83
73
|
const last = emit(inThink ? 'thinking' : 'content', buffer);
|
|
84
|
-
if (last)
|
|
74
|
+
if (last) {
|
|
85
75
|
yield last;
|
|
76
|
+
}
|
|
86
77
|
for (const type of ['thinking', 'content']) {
|
|
87
78
|
const rest = guards[type].flush();
|
|
88
|
-
if (!rest)
|
|
79
|
+
if (!rest) {
|
|
89
80
|
continue;
|
|
90
|
-
|
|
81
|
+
}
|
|
82
|
+
if (type === 'thinking' && unproven !== null) {
|
|
91
83
|
unproven += rest;
|
|
84
|
+
}
|
|
92
85
|
yield { type, text: rest };
|
|
93
86
|
}
|
|
94
87
|
return unproven;
|
|
@@ -6,15 +6,17 @@ export interface RecoveredToolCall {
|
|
|
6
6
|
}
|
|
7
7
|
export declare const MAX_RAW_CALL_CHARS = 4096;
|
|
8
8
|
export declare function clipRawCall(raw: string): string;
|
|
9
|
-
export
|
|
10
|
-
name: string;
|
|
11
|
-
}
|
|
9
|
+
export interface KnownTool {
|
|
10
|
+
readonly name: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function recoverMarkupToolCalls(text: string, knownTools: ReadonlyArray<KnownTool>): RecoveredToolCall[];
|
|
12
13
|
export declare function stripToolCallMarkup(text: string): string;
|
|
13
14
|
export declare function stripToolResponseBlocks(text: string): string;
|
|
14
|
-
export
|
|
15
|
-
name: string;
|
|
16
|
-
arguments?: Record<string, unknown>;
|
|
17
|
-
}
|
|
15
|
+
export interface MarkupToolCall {
|
|
16
|
+
readonly name: string;
|
|
17
|
+
readonly arguments?: Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
export declare function toolCallMarkup(calls: ReadonlyArray<MarkupToolCall>): string;
|
|
18
20
|
export declare function normalizeToolArgs(args: Record<string, unknown>, declaredKeys: ReadonlyArray<string>): Record<string, unknown>;
|
|
19
21
|
export declare function recoverSkillNamedCall(text: string, skillNames: ReadonlyArray<string>, skillToolName: string): RecoveredToolCall[];
|
|
20
22
|
export declare function recoverPrintedSkillLoad(text: string, skillToolName: string): RecoveredToolCall[];
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isRecord } from '../guards.js';
|
|
1
2
|
const FUNCTION_OPEN = '<function=';
|
|
2
3
|
const FUNCTION_CLOSE = '</function>';
|
|
3
4
|
const TOOL_RESPONSE = { open: '<tool_response>', close: '</tool_response>' };
|
|
@@ -9,17 +10,20 @@ function* markupBlocks(text, open, close) {
|
|
|
9
10
|
let cursor = 0;
|
|
10
11
|
for (;;) {
|
|
11
12
|
const start = text.indexOf(open, cursor);
|
|
12
|
-
if (start === -1)
|
|
13
|
+
if (start === -1) {
|
|
13
14
|
return;
|
|
15
|
+
}
|
|
14
16
|
const nameStart = start + open.length;
|
|
15
17
|
cursor = nameStart;
|
|
16
18
|
const name = nameOf(text, nameStart);
|
|
17
|
-
if (name === null)
|
|
19
|
+
if (name === null) {
|
|
18
20
|
continue;
|
|
21
|
+
}
|
|
19
22
|
const bodyStart = nameStart + name.length + 1;
|
|
20
23
|
const bodyEnd = text.indexOf(close, bodyStart);
|
|
21
|
-
if (bodyEnd === -1)
|
|
24
|
+
if (bodyEnd === -1) {
|
|
22
25
|
return;
|
|
26
|
+
}
|
|
23
27
|
yield {
|
|
24
28
|
name: name.trim(),
|
|
25
29
|
body: text.slice(bodyStart, bodyEnd),
|
|
@@ -32,8 +36,9 @@ function* markupBlocks(text, open, close) {
|
|
|
32
36
|
function nameOf(text, nameStart) {
|
|
33
37
|
const window = text.slice(nameStart, nameStart + MAX_NAME_LENGTH + 1);
|
|
34
38
|
const nameEnd = window.indexOf('>');
|
|
35
|
-
if (nameEnd === -1)
|
|
39
|
+
if (nameEnd === -1) {
|
|
36
40
|
return null;
|
|
41
|
+
}
|
|
37
42
|
const name = window.slice(0, nameEnd);
|
|
38
43
|
return name.includes('\n') ? null : name;
|
|
39
44
|
}
|
|
@@ -78,12 +83,14 @@ function stripSpans(text, span) {
|
|
|
78
83
|
let cursor = 0;
|
|
79
84
|
for (;;) {
|
|
80
85
|
const start = hay.indexOf(span.open, cursor);
|
|
81
|
-
if (start === -1)
|
|
86
|
+
if (start === -1) {
|
|
82
87
|
break;
|
|
88
|
+
}
|
|
83
89
|
out += text.slice(cursor, start);
|
|
84
90
|
const end = hay.indexOf(span.close, start + span.open.length);
|
|
85
|
-
if (end === -1)
|
|
91
|
+
if (end === -1) {
|
|
86
92
|
return out;
|
|
93
|
+
}
|
|
87
94
|
cursor = end + span.close.length;
|
|
88
95
|
}
|
|
89
96
|
return out + text.slice(cursor);
|
|
@@ -98,11 +105,13 @@ function danglingIndex(text) {
|
|
|
98
105
|
let cursor = 0;
|
|
99
106
|
for (;;) {
|
|
100
107
|
const start = text.indexOf(FUNCTION_OPEN, cursor);
|
|
101
|
-
if (start === -1)
|
|
108
|
+
if (start === -1) {
|
|
102
109
|
return -1;
|
|
110
|
+
}
|
|
103
111
|
const nameStart = start + FUNCTION_OPEN.length;
|
|
104
|
-
if (nameOf(text, nameStart) !== null)
|
|
112
|
+
if (nameOf(text, nameStart) !== null) {
|
|
105
113
|
return start;
|
|
114
|
+
}
|
|
106
115
|
cursor = nameStart;
|
|
107
116
|
}
|
|
108
117
|
}
|
|
@@ -119,24 +128,27 @@ function encodeMarkupValue(value) {
|
|
|
119
128
|
return JSON.stringify(value ?? null).replace(/</g, '\\u003c');
|
|
120
129
|
}
|
|
121
130
|
const ARG_WRAPPER_KEYS = new Set(['parameters', 'arguments', 'args', 'input', 'params']);
|
|
122
|
-
function
|
|
123
|
-
return value
|
|
131
|
+
function isPlainObject(value) {
|
|
132
|
+
return isRecord(value) && !Array.isArray(value);
|
|
124
133
|
}
|
|
125
134
|
export function normalizeToolArgs(args, declaredKeys) {
|
|
126
|
-
const
|
|
127
|
-
if (
|
|
135
|
+
const [only, ...rest] = Object.keys(args);
|
|
136
|
+
if (only === undefined || rest.length) {
|
|
128
137
|
return args;
|
|
129
|
-
|
|
130
|
-
if (!ARG_WRAPPER_KEYS.has(only) || declaredKeys.includes(only))
|
|
138
|
+
}
|
|
139
|
+
if (!ARG_WRAPPER_KEYS.has(only) || declaredKeys.includes(only)) {
|
|
131
140
|
return args;
|
|
141
|
+
}
|
|
132
142
|
const inner = args[only];
|
|
133
|
-
if (
|
|
143
|
+
if (isPlainObject(inner)) {
|
|
134
144
|
return inner;
|
|
145
|
+
}
|
|
135
146
|
if (typeof inner === 'string') {
|
|
136
147
|
try {
|
|
137
148
|
const parsed = JSON.parse(inner);
|
|
138
|
-
if (
|
|
149
|
+
if (isPlainObject(parsed)) {
|
|
139
150
|
return parsed;
|
|
151
|
+
}
|
|
140
152
|
}
|
|
141
153
|
catch {
|
|
142
154
|
return args;
|
|
@@ -185,17 +197,21 @@ export function recoverPrintedSkillLoad(text, skillToolName) {
|
|
|
185
197
|
catch {
|
|
186
198
|
continue;
|
|
187
199
|
}
|
|
188
|
-
if (!
|
|
200
|
+
if (!isPlainObject(candidate)) {
|
|
189
201
|
continue;
|
|
202
|
+
}
|
|
190
203
|
const keys = Object.keys(candidate);
|
|
191
|
-
if (keys.length === 0 || !keys.every((key) => SKILL_LOAD_KEYS.has(key)))
|
|
204
|
+
if (keys.length === 0 || !keys.every((key) => SKILL_LOAD_KEYS.has(key))) {
|
|
192
205
|
continue;
|
|
206
|
+
}
|
|
193
207
|
const name = candidate.name ?? candidate.skill ?? candidate.skill_name;
|
|
194
208
|
const file = candidate.file ?? candidate.path ?? candidate.filename;
|
|
195
|
-
if (typeof name !== 'string' || typeof file !== 'string')
|
|
209
|
+
if (typeof name !== 'string' || typeof file !== 'string') {
|
|
196
210
|
continue;
|
|
197
|
-
|
|
211
|
+
}
|
|
212
|
+
if (!/\.(md|py)\s*$/i.test(file.replaceAll('"', '').trim())) {
|
|
198
213
|
continue;
|
|
214
|
+
}
|
|
199
215
|
return [
|
|
200
216
|
{
|
|
201
217
|
id: 'recovered-printed-skill-load',
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export declare const INTENT_PARAM = "intent";
|
|
2
2
|
export declare const INTENT_PARAM_DESCRIPTION: string;
|
|
3
3
|
export declare function sanitizeToolIntent(value: unknown): string | undefined;
|
|
4
|
-
export
|
|
4
|
+
export interface TakenToolIntent {
|
|
5
5
|
args: Record<string, unknown>;
|
|
6
6
|
intent?: string;
|
|
7
|
-
}
|
|
7
|
+
}
|
|
8
|
+
export declare function takeToolIntent(args: Record<string, unknown>): TakenToolIntent;
|
|
@@ -8,13 +8,15 @@ export function sanitizeToolIntent(value) {
|
|
|
8
8
|
if (typeof value !== 'string')
|
|
9
9
|
return undefined;
|
|
10
10
|
const collapsed = stripControlTokens(value).replace(/\s+/g, ' ').trim();
|
|
11
|
-
if (!collapsed)
|
|
11
|
+
if (!collapsed) {
|
|
12
12
|
return undefined;
|
|
13
|
+
}
|
|
13
14
|
return collapsed.length > MAX_INTENT_LENGTH ? collapsed.slice(0, MAX_INTENT_LENGTH) : collapsed;
|
|
14
15
|
}
|
|
15
16
|
export function takeToolIntent(args) {
|
|
16
|
-
if (!(INTENT_PARAM in args))
|
|
17
|
+
if (!(INTENT_PARAM in args)) {
|
|
17
18
|
return { args };
|
|
19
|
+
}
|
|
18
20
|
const { [INTENT_PARAM]: raw, ...rest } = args;
|
|
19
21
|
const intent = sanitizeToolIntent(raw);
|
|
20
22
|
return intent === undefined ? { args: rest } : { args: rest, intent };
|
|
@@ -33,29 +33,33 @@ function normalizeModelLabel(raw) {
|
|
|
33
33
|
.split(/\r?\n/)
|
|
34
34
|
.map((line) => line.trim())
|
|
35
35
|
.find(Boolean);
|
|
36
|
-
if (!firstLine)
|
|
36
|
+
if (!firstLine) {
|
|
37
37
|
return null;
|
|
38
|
+
}
|
|
38
39
|
const unlabeled = firstLine.replace(/^label\s*[:\-–]\s*/i, '');
|
|
39
40
|
const unquoted = unwrap(unlabeled)
|
|
40
41
|
.replace(/^["'`]+|["'`]+$/g, '')
|
|
41
42
|
.trim();
|
|
42
43
|
const words = unquoted.split(/\s+/).filter(Boolean).slice(0, MAX_LABEL_WORDS);
|
|
43
|
-
if (words.length === 0)
|
|
44
|
+
if (words.length === 0) {
|
|
44
45
|
return null;
|
|
46
|
+
}
|
|
45
47
|
const label = words
|
|
46
48
|
.join(' ')
|
|
47
49
|
.replace(/[.,;:!?]+$/, '')
|
|
48
50
|
.trim()
|
|
49
51
|
.slice(0, MAX_LABEL_LENGTH)
|
|
50
52
|
.trim();
|
|
51
|
-
if (!label || ECHOED_INSTRUCTION.test(label))
|
|
53
|
+
if (!label || ECHOED_INSTRUCTION.test(label)) {
|
|
52
54
|
return null;
|
|
55
|
+
}
|
|
53
56
|
return label;
|
|
54
57
|
}
|
|
55
58
|
export function skillCallLabel(args) {
|
|
56
59
|
const name = stringArg(args, 'name') || stringArg(args, 'skill_name') || stringArg(args, 'skill');
|
|
57
|
-
if (!name)
|
|
60
|
+
if (!name) {
|
|
58
61
|
return 'Load skill instructions';
|
|
62
|
+
}
|
|
59
63
|
const title = titleSkillName(name);
|
|
60
64
|
const file = stringArg(args, 'file');
|
|
61
65
|
return file ? `Read ${title}/${fileName(file)}` : `Load ${title}`;
|
|
@@ -65,8 +69,9 @@ export function isSkillTool(name) {
|
|
|
65
69
|
}
|
|
66
70
|
function stringArg(args, key) {
|
|
67
71
|
const value = args[key];
|
|
68
|
-
if (typeof value !== 'string')
|
|
72
|
+
if (typeof value !== 'string') {
|
|
69
73
|
return '';
|
|
74
|
+
}
|
|
70
75
|
return unquoteArg(value).trim();
|
|
71
76
|
}
|
|
72
77
|
function fileName(path) {
|
|
@@ -82,8 +87,9 @@ function titleSkillName(name) {
|
|
|
82
87
|
}
|
|
83
88
|
function normalizeModelDescription(raw) {
|
|
84
89
|
const text = stripControlTokens(raw).replace(/\s+/g, ' ').trim();
|
|
85
|
-
if (!text || ECHOED_INSTRUCTION.test(text))
|
|
90
|
+
if (!text || ECHOED_INSTRUCTION.test(text)) {
|
|
86
91
|
return undefined;
|
|
92
|
+
}
|
|
87
93
|
return text.length > MAX_DESCRIPTION_LENGTH
|
|
88
94
|
? `${text.slice(0, MAX_DESCRIPTION_LENGTH).trimEnd()}…`
|
|
89
95
|
: text;
|
|
@@ -94,8 +100,9 @@ export function parseToolLabelResponse(raw) {
|
|
|
94
100
|
try {
|
|
95
101
|
const parsed = JSON.parse(trimmed);
|
|
96
102
|
const label = typeof parsed.label === 'string' ? normalizeModelLabel(parsed.label) : null;
|
|
97
|
-
if (!label)
|
|
103
|
+
if (!label) {
|
|
98
104
|
return null;
|
|
105
|
+
}
|
|
99
106
|
const description = typeof parsed.description === 'string'
|
|
100
107
|
? normalizeModelDescription(parsed.description)
|
|
101
108
|
: undefined;
|
|
@@ -108,11 +115,13 @@ export function parseToolLabelResponse(raw) {
|
|
|
108
115
|
return label ? { label } : null;
|
|
109
116
|
}
|
|
110
117
|
export function fallbackToolLabel(name, args = {}) {
|
|
111
|
-
if (isSkillTool(name))
|
|
118
|
+
if (isSkillTool(name)) {
|
|
112
119
|
return skillCallLabel(args);
|
|
120
|
+
}
|
|
113
121
|
const query = stringArg(args, 'query');
|
|
114
|
-
if (query)
|
|
122
|
+
if (query) {
|
|
115
123
|
return `Search ${query}`.slice(0, MAX_LABEL_LENGTH).trim();
|
|
124
|
+
}
|
|
116
125
|
const url = stringArg(args, 'url');
|
|
117
126
|
if (url) {
|
|
118
127
|
const method = stringArg(args, 'method').toUpperCase();
|