@qvac/harness 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +689 -141
- package/README.md +29 -7
- package/dist/harness.bundle +71 -50
- package/dist-lib/index.d.ts +36 -39
- package/dist-lib/index.js +279 -114
- 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 +11 -32
- package/dist-lib/lib/connect.js +152 -112
- package/dist-lib/lib/context-window.js +25 -21
- package/dist-lib/lib/contract-types.d.ts +22 -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 +13 -20
- package/dist-lib/lib/models/model-catalog.js +59 -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 +44 -10
- package/dist-lib/lib/models/model-pool.js +47 -42
- 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 +110 -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 +14 -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 +3 -0
- package/dist-lib/spec/calls.js +1 -0
- package/dist-lib/spec/hrpc/hrpc.json +13 -0
- package/dist-lib/spec/hrpc/index.js +15 -3
- package/dist-lib/spec/hrpc/messages.js +39 -8
- package/dist-lib/spec/hyperschema/index.js +39 -8
- package/dist-lib/spec/hyperschema/schema.json +30 -1
- package/dist-lib/spec/hyperschema/types.d.ts +9 -1
- package/package.json +13 -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
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import process from 'process';
|
|
2
2
|
import { contextCandidates } from '../context-window.js';
|
|
3
|
-
import { errorCode, errorMessage } from '../
|
|
3
|
+
import { errorCode, errorMessage, isRecord } from '../guards.js';
|
|
4
4
|
import { bufferBurst } from '../helpers/buffer-burst.js';
|
|
5
5
|
import { endsTurn, stopAtControlToken, stripControlTokens, truncateAtControlToken } from '../helpers/control-tokens.js';
|
|
6
6
|
import { createMarkupStreamFilter } from '../helpers/markup-stream-filter.js';
|
|
7
7
|
import { AbortedError, raceAbort } from '../helpers/race-abort.js';
|
|
8
|
+
import { raceTimeout } from '../helpers/race-timeout.js';
|
|
8
9
|
import { createRunOutcomeTracker, degenerateAnswer, unnamedWrites, writeReport } from '../helpers/run-outcome.js';
|
|
9
10
|
import { splitThinking } from '../helpers/thinking.js';
|
|
10
11
|
import { clipRawCall, normalizeToolArgs, recoverMarkupToolCalls, recoverPrintedSkillLoad, recoverSkillNamedCall, stripToolCallMarkup, stripToolResponseBlocks, toolCallMarkup } from '../helpers/tool-call-markup.js';
|
|
@@ -16,7 +17,7 @@ import { resolveLlmGenerationParams } from '../models/llm-presets.js';
|
|
|
16
17
|
import { customToolDialect } from '../models/model-catalog.js';
|
|
17
18
|
import { isContextOverflowError, isSdkModelWedgedError } from '../models/sdk-faults.js';
|
|
18
19
|
import { annotateLastUserTime, skillsPromptSection, systemPromptParts } from '../prompt.js';
|
|
19
|
-
import { isMetadataMethod } from '../tools/mcp/
|
|
20
|
+
import { isMetadataMethod } from '../tools/mcp/protocol.js';
|
|
20
21
|
import { unquoteArg } from '../tools/model-args.js';
|
|
21
22
|
import { SKILL_TOOL_NAME, WEB_SEARCH_TOOL_NAME } from './tool-names.js';
|
|
22
23
|
import { mainFileRequested, skillFileArg, skillFileStem } from '../tools/skill.js';
|
|
@@ -33,14 +34,18 @@ export function imageSettingsFrom(agent) {
|
|
|
33
34
|
if (!agent)
|
|
34
35
|
return undefined;
|
|
35
36
|
const settings = {};
|
|
36
|
-
if (agent.imageModelChoice)
|
|
37
|
+
if (agent.imageModelChoice) {
|
|
37
38
|
settings.modelChoice = agent.imageModelChoice;
|
|
38
|
-
|
|
39
|
+
}
|
|
40
|
+
if (agent.imageSteps) {
|
|
39
41
|
settings.steps = agent.imageSteps;
|
|
40
|
-
|
|
42
|
+
}
|
|
43
|
+
if (agent.imageWidth) {
|
|
41
44
|
settings.width = agent.imageWidth;
|
|
42
|
-
|
|
45
|
+
}
|
|
46
|
+
if (agent.imageHeight) {
|
|
43
47
|
settings.height = agent.imageHeight;
|
|
48
|
+
}
|
|
44
49
|
return Object.keys(settings).length ? settings : undefined;
|
|
45
50
|
}
|
|
46
51
|
const BURST_WINDOW_MS = 100;
|
|
@@ -62,10 +67,12 @@ export function trustedSourcesFrom(history) {
|
|
|
62
67
|
const sources = [];
|
|
63
68
|
for (const entry of history) {
|
|
64
69
|
const text = String(entry.content ?? '');
|
|
65
|
-
if (entry.role === 'user')
|
|
70
|
+
if (entry.role === 'user') {
|
|
66
71
|
sources.push({ origin: 'user', text });
|
|
67
|
-
|
|
72
|
+
}
|
|
73
|
+
else if (entry.role === 'tool') {
|
|
68
74
|
sources.push({ origin: originOfToolTurn(text), text });
|
|
75
|
+
}
|
|
69
76
|
}
|
|
70
77
|
return sources;
|
|
71
78
|
}
|
|
@@ -102,16 +109,18 @@ function sanitizeTurn(turn) {
|
|
|
102
109
|
function lastUserContent(messages) {
|
|
103
110
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
104
111
|
const turn = messages[i];
|
|
105
|
-
if (turn?.role === 'user')
|
|
112
|
+
if (turn?.role === 'user') {
|
|
106
113
|
return turn.content;
|
|
114
|
+
}
|
|
107
115
|
}
|
|
108
116
|
return '';
|
|
109
117
|
}
|
|
110
118
|
function lastUserImages(messages) {
|
|
111
119
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
112
120
|
const turn = messages[i];
|
|
113
|
-
if (turn?.role === 'user')
|
|
121
|
+
if (turn?.role === 'user') {
|
|
114
122
|
return turn.attachments ?? [];
|
|
123
|
+
}
|
|
115
124
|
}
|
|
116
125
|
return [];
|
|
117
126
|
}
|
|
@@ -149,8 +158,9 @@ function assistantToolTurn(contentText, calls) {
|
|
|
149
158
|
function preloadLastUser(messages, name, body) {
|
|
150
159
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
151
160
|
const turn = messages[i];
|
|
152
|
-
if (turn?.role !== 'user')
|
|
161
|
+
if (turn?.role !== 'user') {
|
|
153
162
|
continue;
|
|
163
|
+
}
|
|
154
164
|
const next = [...messages];
|
|
155
165
|
next[i] = { ...turn, content: skillPreloadMessage(turn.content, name, body) };
|
|
156
166
|
return next;
|
|
@@ -159,10 +169,12 @@ function preloadLastUser(messages, name, body) {
|
|
|
159
169
|
}
|
|
160
170
|
function collectStats(state, stats, stopReason) {
|
|
161
171
|
state.stopReason = stopReason;
|
|
162
|
-
if (!stats)
|
|
172
|
+
if (!stats) {
|
|
163
173
|
return;
|
|
164
|
-
|
|
174
|
+
}
|
|
175
|
+
if (state.ttft === undefined && stats.timeToFirstToken) {
|
|
165
176
|
state.ttft = stats.timeToFirstToken;
|
|
177
|
+
}
|
|
166
178
|
if (state.promptTokensPerSecond === undefined && stats.promptTokensPerSecond) {
|
|
167
179
|
state.promptTokensPerSecond = stats.promptTokensPerSecond;
|
|
168
180
|
}
|
|
@@ -173,10 +185,12 @@ function collectStats(state, stats, stopReason) {
|
|
|
173
185
|
state.timedTokens += stats.generatedTokens;
|
|
174
186
|
}
|
|
175
187
|
}
|
|
176
|
-
if (stats.promptTokens)
|
|
188
|
+
if (stats.promptTokens) {
|
|
177
189
|
state.promptTokens = stats.promptTokens;
|
|
178
|
-
|
|
190
|
+
}
|
|
191
|
+
if (stats.cacheTokens) {
|
|
179
192
|
state.cacheTokens = stats.cacheTokens;
|
|
193
|
+
}
|
|
180
194
|
}
|
|
181
195
|
function metricsEvent(state, usage) {
|
|
182
196
|
if (!state.tokens)
|
|
@@ -190,10 +204,10 @@ function metricsEvent(state, usage) {
|
|
|
190
204
|
tokensPerSecond: state.durationMs > 0 ? (state.timedTokens / state.durationMs) * 1000 : undefined,
|
|
191
205
|
promptTokens: state.promptTokens,
|
|
192
206
|
cacheTokens: state.cacheTokens,
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
207
|
+
ctxSize: state.ctxSize || undefined,
|
|
208
|
+
backends: state.backends.length ? state.backends : undefined,
|
|
209
|
+
usage: usage ?? undefined,
|
|
210
|
+
stopReason: state.stopReason || undefined
|
|
197
211
|
};
|
|
198
212
|
}
|
|
199
213
|
const TOOL_DENIED_MESSAGE = 'The user declined this call. Do not retry it or call it with different arguments to get ' +
|
|
@@ -215,16 +229,17 @@ const RETRYABLE_CODE = new Set(['timeout', 'transport', 'busy']);
|
|
|
215
229
|
function callSucceeded(result, outcome) {
|
|
216
230
|
if (outcome.kind !== 'success')
|
|
217
231
|
return false;
|
|
218
|
-
const exitCode = result
|
|
232
|
+
const exitCode = isRecord(result) ? result.exitCode : undefined;
|
|
219
233
|
return typeof exitCode !== 'number' || exitCode === 0;
|
|
220
234
|
}
|
|
221
235
|
function retryHints(result) {
|
|
222
236
|
if (!result || typeof result !== 'object' || Array.isArray(result))
|
|
223
237
|
return {};
|
|
224
|
-
const
|
|
238
|
+
const status = 'status' in result ? result.status : undefined;
|
|
239
|
+
const code = 'code' in result ? result.code : undefined;
|
|
225
240
|
return {
|
|
226
|
-
|
|
227
|
-
|
|
241
|
+
status: typeof status === 'number' ? status : undefined,
|
|
242
|
+
code: typeof code === 'string' ? code : undefined
|
|
228
243
|
};
|
|
229
244
|
}
|
|
230
245
|
function settledFailure(result, outcome) {
|
|
@@ -233,8 +248,9 @@ function settledFailure(result, outcome) {
|
|
|
233
248
|
if (outcome.kind === 'error' && outcome.error !== undefined)
|
|
234
249
|
return false;
|
|
235
250
|
const { code, status } = retryHints(result);
|
|
236
|
-
if (code !== undefined && RETRYABLE_CODE.has(code))
|
|
251
|
+
if (code !== undefined && RETRYABLE_CODE.has(code)) {
|
|
237
252
|
return false;
|
|
253
|
+
}
|
|
238
254
|
return status === undefined || (status < 500 && !RETRYABLE_STATUS.has(status));
|
|
239
255
|
}
|
|
240
256
|
const MAX_BLOCKED_REPEATS = 3;
|
|
@@ -257,13 +273,14 @@ function deniedCall() {
|
|
|
257
273
|
executed: false
|
|
258
274
|
});
|
|
259
275
|
}
|
|
260
|
-
async function executeCall(tool, args, ctx,
|
|
276
|
+
async function executeCall(tool, args, { ctx, approve, signal, denied, sources = [], effect: classified, skipApprovals, onToolActivity, intent, display }) {
|
|
261
277
|
const validationError = tool.validate?.(args, ctx);
|
|
262
278
|
if (validationError) {
|
|
263
279
|
hlog('tool rejected: arguments failed validation', { tool: tool.name });
|
|
264
280
|
return guidanceResult(validationError);
|
|
265
281
|
}
|
|
266
|
-
const refusal = guardToolCall(tool.name, args,
|
|
282
|
+
const refusal = guardToolCall(tool.name, args, {
|
|
283
|
+
sources,
|
|
267
284
|
externalWrite: tool.externalWrite === true
|
|
268
285
|
});
|
|
269
286
|
if (refusal) {
|
|
@@ -304,13 +321,11 @@ async function executeCall(tool, args, ctx, { approve, signal, denied, sources =
|
|
|
304
321
|
}), signal)
|
|
305
322
|
: false);
|
|
306
323
|
hlog(`tool ${approved ? 'approved' : 'denied'}`, { tool: tool.name });
|
|
307
|
-
const decision =
|
|
308
|
-
|
|
309
|
-
: skipApprovals === true
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
? 'allowed'
|
|
313
|
-
: 'denied';
|
|
324
|
+
const decision = toolDecision({
|
|
325
|
+
auto: tool.autoApprove === true || effect === 'read',
|
|
326
|
+
skipAll: skipApprovals === true,
|
|
327
|
+
approved
|
|
328
|
+
});
|
|
314
329
|
onToolActivity?.({
|
|
315
330
|
type: 'tool-activity',
|
|
316
331
|
name: tool.name,
|
|
@@ -343,15 +358,15 @@ function runToolContext(scope) {
|
|
|
343
358
|
return (turnImages = [], ctxSize) => ({
|
|
344
359
|
agentId: agent?.id ?? null,
|
|
345
360
|
ctxSize,
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
361
|
+
image,
|
|
362
|
+
turnImages: turnImages.length ? turnImages : undefined,
|
|
363
|
+
attach,
|
|
364
|
+
fetchAttachment,
|
|
365
|
+
ragSearch,
|
|
366
|
+
progress,
|
|
367
|
+
askUser,
|
|
368
|
+
signal,
|
|
369
|
+
runBudget
|
|
355
370
|
});
|
|
356
371
|
}
|
|
357
372
|
function labelOf(name, args, emoji) {
|
|
@@ -394,24 +409,21 @@ function blockedSkillMessage(name, catalog, listShown) {
|
|
|
394
409
|
`skill is available this turn — do not guess another name, and answer from what you ` +
|
|
395
410
|
`already have.`;
|
|
396
411
|
}
|
|
397
|
-
async function resolveToolCalls(toolCalls, enabled, agentId, pipeline, skillNames,
|
|
412
|
+
async function resolveToolCalls(toolCalls, { enabled, agentId, pipeline, skillNames, sandboxMode, signal }) {
|
|
398
413
|
const resolved = [];
|
|
399
414
|
for (const call of toolCalls) {
|
|
400
415
|
if (signal?.aborted)
|
|
401
416
|
throw new AbortedError();
|
|
402
417
|
const tool = enabled.find((t) => t.name === call.name);
|
|
418
|
+
const rawCall = call.raw === undefined ? undefined : clipRawCall(call.raw);
|
|
403
419
|
if (!tool) {
|
|
404
420
|
const { args } = takeToolIntent(call.arguments);
|
|
405
|
-
resolved.push({
|
|
406
|
-
call,
|
|
407
|
-
args,
|
|
408
|
-
...(call.raw === undefined ? {} : { rawCall: clipRawCall(call.raw) })
|
|
409
|
-
});
|
|
421
|
+
resolved.push({ call, args, rawCall });
|
|
410
422
|
continue;
|
|
411
423
|
}
|
|
412
424
|
const taken = takeToolIntent(call.arguments);
|
|
413
425
|
const args = normalizeToolArgs(taken.args, Object.keys(tool.parameters.properties));
|
|
414
|
-
const
|
|
426
|
+
const intent = taken.intent || undefined;
|
|
415
427
|
const fold = await pipeline.runPreToolFold({
|
|
416
428
|
toolName: tool.name,
|
|
417
429
|
args,
|
|
@@ -422,37 +434,27 @@ async function resolveToolCalls(toolCalls, enabled, agentId, pipeline, skillName
|
|
|
422
434
|
signal
|
|
423
435
|
});
|
|
424
436
|
resolved.push(fold.ok
|
|
425
|
-
? {
|
|
426
|
-
|
|
427
|
-
tool,
|
|
428
|
-
args: fold.args,
|
|
429
|
-
...(call.raw === undefined ? {} : { rawCall: clipRawCall(call.raw) }),
|
|
430
|
-
...(intent ? { intent } : {})
|
|
431
|
-
}
|
|
432
|
-
: {
|
|
433
|
-
call,
|
|
434
|
-
tool,
|
|
435
|
-
args,
|
|
436
|
-
rejection: fold.rejection,
|
|
437
|
-
...(call.raw === undefined ? {} : { rawCall: clipRawCall(call.raw) }),
|
|
438
|
-
...(intent ? { intent } : {})
|
|
439
|
-
});
|
|
437
|
+
? { call, tool, args: fold.args, rawCall, intent }
|
|
438
|
+
: { call, tool, args, rejection: fold.rejection, rawCall, intent });
|
|
440
439
|
}
|
|
441
440
|
return resolved;
|
|
442
441
|
}
|
|
443
442
|
function unprovenReplay(state, final) {
|
|
444
443
|
if (!state.unproven)
|
|
445
444
|
return null;
|
|
446
|
-
if (state.stopToken)
|
|
445
|
+
if (state.stopToken) {
|
|
447
446
|
return endsTurn(state.stopToken) ? state.unproven : null;
|
|
448
|
-
|
|
447
|
+
}
|
|
448
|
+
if (final.stopReason === 'length' || final.stopReason === 'cancelled') {
|
|
449
449
|
return null;
|
|
450
|
+
}
|
|
450
451
|
return state.unproven;
|
|
451
452
|
}
|
|
452
|
-
async function* runRoundTokens(
|
|
453
|
+
async function* runRoundTokens(result, state, { sdk, signal, startInThink = false }) {
|
|
453
454
|
const cancelThisRound = () => {
|
|
454
|
-
if (result.requestId)
|
|
455
|
+
if (result.requestId) {
|
|
455
456
|
sdk.cancel?.({ requestId: result.requestId });
|
|
457
|
+
}
|
|
456
458
|
};
|
|
457
459
|
signal?.addEventListener('abort', cancelThisRound, { once: true });
|
|
458
460
|
const tokens = stopAtControlToken(result.tokenStream, (token) => {
|
|
@@ -467,27 +469,33 @@ async function* runRoundTokens(sdk, result, state, signal, startInThink = false)
|
|
|
467
469
|
const next = await events.next();
|
|
468
470
|
if (next.done) {
|
|
469
471
|
state.unproven = next.value;
|
|
470
|
-
const thinkingTail = thinkingFilter.flush();
|
|
471
|
-
if (thinkingTail)
|
|
472
|
-
yield { type: 'thinking', text: thinkingTail };
|
|
473
|
-
const contentTail = contentFilter.flush();
|
|
474
|
-
if (contentTail)
|
|
475
|
-
yield { type: 'content', text: contentTail };
|
|
476
472
|
break;
|
|
477
473
|
}
|
|
478
|
-
if (signal?.aborted)
|
|
474
|
+
if (signal?.aborted) {
|
|
479
475
|
throw new AbortedError();
|
|
476
|
+
}
|
|
480
477
|
tokenEvents++;
|
|
481
|
-
if (next.value.type === 'content')
|
|
478
|
+
if (next.value.type === 'content') {
|
|
482
479
|
state.rawContentText += next.value.text;
|
|
480
|
+
}
|
|
483
481
|
const filter = next.value.type === 'thinking' ? thinkingFilter : contentFilter;
|
|
484
482
|
const text = filter.push(next.value.text);
|
|
485
|
-
if (text)
|
|
483
|
+
if (text) {
|
|
486
484
|
yield { type: next.value.type, text };
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
const thinkingTail = thinkingFilter.flush();
|
|
488
|
+
if (thinkingTail) {
|
|
489
|
+
yield { type: 'thinking', text: thinkingTail };
|
|
490
|
+
}
|
|
491
|
+
const contentTail = contentFilter.flush();
|
|
492
|
+
if (contentTail) {
|
|
493
|
+
yield { type: 'content', text: contentTail };
|
|
487
494
|
}
|
|
488
495
|
hlog('stream ended', { events: tokenEvents, stopToken: state.stopToken });
|
|
489
|
-
if (state.stopToken)
|
|
496
|
+
if (state.stopToken) {
|
|
490
497
|
cancelThisRound();
|
|
498
|
+
}
|
|
491
499
|
}
|
|
492
500
|
finally {
|
|
493
501
|
signal?.removeEventListener('abort', cancelThisRound);
|
|
@@ -512,17 +520,13 @@ function roundTokens(stats) {
|
|
|
512
520
|
const TRUNCATED_FINAL_MS = 2000;
|
|
513
521
|
function truncatedFinal(final, contentText) {
|
|
514
522
|
const accepted = { contentText, toolCalls: [], raw: { fullText: contentText } };
|
|
515
|
-
let timer;
|
|
516
|
-
const expired = new Promise((resolve) => {
|
|
517
|
-
timer = setTimeout(() => resolve(accepted), TRUNCATED_FINAL_MS);
|
|
518
|
-
});
|
|
519
523
|
const guarded = final.catch((err) => {
|
|
520
524
|
if (isSdkModelWedgedError(err))
|
|
521
525
|
throw err;
|
|
522
526
|
return accepted;
|
|
523
527
|
});
|
|
524
528
|
guarded.catch(noop);
|
|
525
|
-
return
|
|
529
|
+
return raceTimeout(guarded, { ms: TRUNCATED_FINAL_MS, fallback: accepted });
|
|
526
530
|
}
|
|
527
531
|
async function* runRecoveredRound(sdk, args) {
|
|
528
532
|
const lease = args.acquireRound ? await args.acquireRound() : null;
|
|
@@ -573,9 +577,12 @@ async function* runRecoveredRoundWith(sdk, args, modelId) {
|
|
|
573
577
|
const result = sdk.completion(params);
|
|
574
578
|
result.final.catch(noop);
|
|
575
579
|
const startInThink = args.generationParams?.reasoning_budget === -1;
|
|
576
|
-
for await (const event of runRoundTokens(
|
|
577
|
-
|
|
578
|
-
|
|
580
|
+
for await (const event of runRoundTokens(result, state, {
|
|
581
|
+
sdk,
|
|
582
|
+
signal: args.signal,
|
|
583
|
+
startInThink
|
|
584
|
+
})) {
|
|
585
|
+
contentText += event.type === 'content' ? event.text : '';
|
|
579
586
|
emitted = true;
|
|
580
587
|
yield event;
|
|
581
588
|
}
|
|
@@ -618,24 +625,28 @@ async function* runRecoveredRoundWith(sdk, args, modelId) {
|
|
|
618
625
|
messages: undefined,
|
|
619
626
|
tokens: undefined,
|
|
620
627
|
outcome: isContextOverflowError(err) ? 'overflowed' : 'failed',
|
|
621
|
-
reason:
|
|
628
|
+
reason: errorMessage(err)
|
|
622
629
|
};
|
|
623
630
|
}
|
|
624
|
-
if (!isContextOverflowError(err))
|
|
631
|
+
if (!isContextOverflowError(err)) {
|
|
625
632
|
throw err;
|
|
626
|
-
|
|
633
|
+
}
|
|
634
|
+
if (emitted) {
|
|
627
635
|
throw new Error(CONTEXT_OVERFLOW_MESSAGE, { cause: err });
|
|
636
|
+
}
|
|
628
637
|
lastOverflow = err;
|
|
629
638
|
}
|
|
630
639
|
}
|
|
631
|
-
if (lastOverflow)
|
|
640
|
+
if (lastOverflow) {
|
|
632
641
|
throw new Error(CONTEXT_OVERFLOW_MESSAGE, { cause: lastOverflow });
|
|
642
|
+
}
|
|
633
643
|
throw new Error('context recovery produced no completion candidate');
|
|
634
644
|
}
|
|
635
645
|
function* reportUnnamedWrites(said, landed) {
|
|
636
646
|
const unreported = writeReport(unnamedWrites(said, landed));
|
|
637
|
-
if (unreported)
|
|
647
|
+
if (unreported) {
|
|
638
648
|
yield { type: 'content', text: unreported };
|
|
649
|
+
}
|
|
639
650
|
}
|
|
640
651
|
export async function* completion(sdk, { modelId, acquireRound, model, agent, ctxSize, cacheKey, thinkingDefault, generationParams: generationParamsOverride, responseFormat, messages: storedMessages, tools: allTools = [], skillCatalog = [], approve, attach, fetchAttachment, ragSearch, progress, askUser, signal, toolConfigs, fsRoots = [], fsWriteRoots = [], captureInferenceCalls = false }) {
|
|
641
652
|
const pipeline = new HookPipeline();
|
|
@@ -654,7 +665,7 @@ export async function* completion(sdk, { modelId, acquireRound, model, agent, ct
|
|
|
654
665
|
let runError;
|
|
655
666
|
const runOutcomes = createRunOutcomeTracker();
|
|
656
667
|
const landed = runOutcomes.confirmedWrites;
|
|
657
|
-
|
|
668
|
+
async function* runTurn() {
|
|
658
669
|
if (signal?.aborted)
|
|
659
670
|
throw new AbortedError();
|
|
660
671
|
await pipeline.onRunStart({ agentId, messages });
|
|
@@ -702,8 +713,8 @@ export async function* completion(sdk, { modelId, acquireRound, model, agent, ct
|
|
|
702
713
|
hasActiveSkills: activeSkills.length > 0
|
|
703
714
|
});
|
|
704
715
|
}
|
|
705
|
-
const reasoningEnabled = agent?.reasoning
|
|
706
|
-
const deviceReasoning = thinkingDefault
|
|
716
|
+
const reasoningEnabled = reasoningFlag(agent?.reasoning);
|
|
717
|
+
const deviceReasoning = reasoningFlag(thinkingDefault);
|
|
707
718
|
const resolvedGenerationParams = resolveLlmGenerationParams(model, reasoningEnabled, deviceReasoning);
|
|
708
719
|
const generationParams = generationParamsOverride
|
|
709
720
|
? { ...resolvedGenerationParams, ...generationParamsOverride }
|
|
@@ -714,6 +725,24 @@ export async function* completion(sdk, { modelId, acquireRound, model, agent, ct
|
|
|
714
725
|
let skillIcon = null;
|
|
715
726
|
const skillEmoji = (name) => skillCatalog.find((entry) => entry.name === name)?.emoji ?? null;
|
|
716
727
|
const nudgedSkills = new Set();
|
|
728
|
+
function recordSkillLoad(skillName, output, { mainRequested, askedFile }) {
|
|
729
|
+
if (!output || typeof output !== 'object' || !('content' in output)) {
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
loadedSkills.add(skillName);
|
|
733
|
+
if ('file' in output && typeof output.file === 'string') {
|
|
734
|
+
const files = loadedSkillFiles.get(skillName) ?? new Set();
|
|
735
|
+
files.add(output.file);
|
|
736
|
+
loadedSkillFiles.set(skillName, files);
|
|
737
|
+
}
|
|
738
|
+
if (mainRequested) {
|
|
739
|
+
loadedThisTurn.add(skillName);
|
|
740
|
+
}
|
|
741
|
+
else {
|
|
742
|
+
loadedFilesThisTurn.add(fileKey(skillName, unquoteArg(askedFile)));
|
|
743
|
+
}
|
|
744
|
+
skillIcon = skillEmoji(skillName) ?? skillIcon;
|
|
745
|
+
}
|
|
717
746
|
const toolDialect = model ? customToolDialect(model) : undefined;
|
|
718
747
|
let turns = messages;
|
|
719
748
|
let preloadedSkill = null;
|
|
@@ -802,8 +831,9 @@ export async function* completion(sdk, { modelId, acquireRound, model, agent, ct
|
|
|
802
831
|
let blockedRepeats = 0;
|
|
803
832
|
let webSearches = 0;
|
|
804
833
|
const sources = trustedSourcesFrom(messages);
|
|
805
|
-
if (preloadedSkill)
|
|
834
|
+
if (preloadedSkill) {
|
|
806
835
|
sources.push({ origin: 'skill', text: preloadedSkill });
|
|
836
|
+
}
|
|
807
837
|
const query = explicitWebSearchQuery(lastUserContent(messages), enabled, {
|
|
808
838
|
skillPreloaded: preloadedSkill !== null
|
|
809
839
|
});
|
|
@@ -820,8 +850,9 @@ export async function* completion(sdk, { modelId, acquireRound, model, agent, ct
|
|
|
820
850
|
const searchEffect = webSearch.effect(args);
|
|
821
851
|
const searchResource = webSearch.resource?.(args) ?? null;
|
|
822
852
|
const searchCallDisplay = labelOf(webSearch.name, args, null);
|
|
823
|
-
if (signal?.aborted)
|
|
853
|
+
if (signal?.aborted) {
|
|
824
854
|
throw new AbortedError();
|
|
855
|
+
}
|
|
825
856
|
yield {
|
|
826
857
|
type: 'tool-call',
|
|
827
858
|
name: webSearch.name,
|
|
@@ -831,7 +862,8 @@ export async function* completion(sdk, { modelId, acquireRound, model, agent, ct
|
|
|
831
862
|
};
|
|
832
863
|
let activity = null;
|
|
833
864
|
const execution = fold.ok
|
|
834
|
-
? await executeCall(webSearch, args,
|
|
865
|
+
? await executeCall(webSearch, args, {
|
|
866
|
+
ctx: toolContext(turnImages, ctxSize),
|
|
835
867
|
approve,
|
|
836
868
|
signal,
|
|
837
869
|
denied,
|
|
@@ -854,8 +886,9 @@ export async function* completion(sdk, { modelId, acquireRound, model, agent, ct
|
|
|
854
886
|
const executionOutcome = settled.outcome;
|
|
855
887
|
runOutcomes.record(output, executionOutcome);
|
|
856
888
|
runOutcomes.finishRound();
|
|
857
|
-
if (fold.ok)
|
|
889
|
+
if (fold.ok) {
|
|
858
890
|
webSearches++;
|
|
891
|
+
}
|
|
859
892
|
if (!activity && !fold.ok) {
|
|
860
893
|
activity = {
|
|
861
894
|
type: 'tool-activity',
|
|
@@ -866,8 +899,9 @@ export async function* completion(sdk, { modelId, acquireRound, model, agent, ct
|
|
|
866
899
|
decision: 'blocked'
|
|
867
900
|
};
|
|
868
901
|
}
|
|
869
|
-
if (activity)
|
|
902
|
+
if (activity) {
|
|
870
903
|
yield activity;
|
|
904
|
+
}
|
|
871
905
|
yield {
|
|
872
906
|
type: 'tool-result',
|
|
873
907
|
name: webSearch.name,
|
|
@@ -920,11 +954,12 @@ export async function* completion(sdk, { modelId, acquireRound, model, agent, ct
|
|
|
920
954
|
});
|
|
921
955
|
roundsSent = round + 1;
|
|
922
956
|
const final = recovered.final;
|
|
923
|
-
if (!recovered.cacheable)
|
|
957
|
+
if (!recovered.cacheable) {
|
|
924
958
|
roundCacheKey = undefined;
|
|
959
|
+
}
|
|
925
960
|
history = recovered.history;
|
|
926
961
|
collectStats(stats, final.stats, final.stopReason);
|
|
927
|
-
hlog('round stats', { round, wallMs: Date.now() - roundStarted, ...
|
|
962
|
+
hlog('round stats', { round, wallMs: Date.now() - roundStarted, ...final.stats });
|
|
928
963
|
const markup = stripToolResponseBlocks(truncateAtControlToken(final.raw.fullText) || recovered.unproven || '');
|
|
929
964
|
let toolCalls = final.toolCalls?.length
|
|
930
965
|
? final.toolCalls
|
|
@@ -935,24 +970,29 @@ export async function* completion(sdk, { modelId, acquireRound, model, agent, ct
|
|
|
935
970
|
const alreadyLoaded = rescuedArgs !== undefined &&
|
|
936
971
|
(loadedSkillFiles.get(unquoteArg(rescuedArgs.name))?.has(unquoteArg(rescuedArgs.file)) ??
|
|
937
972
|
false);
|
|
938
|
-
if (!alreadyLoaded)
|
|
973
|
+
if (!alreadyLoaded) {
|
|
939
974
|
toolCalls = rescued;
|
|
940
|
-
|
|
975
|
+
}
|
|
976
|
+
if (toolCalls.length) {
|
|
941
977
|
hlog('recovered printed skill load', { round });
|
|
978
|
+
}
|
|
942
979
|
}
|
|
943
980
|
if (!toolCalls.length && enabled.some((tool) => tool.name === SKILL_TOOL_NAME)) {
|
|
944
981
|
toolCalls = recoverSkillNamedCall(markup, inContextSkills
|
|
945
982
|
.filter((skill) => !nudgedSkills.has(skill.name))
|
|
946
983
|
.map((skill) => skill.name), SKILL_TOOL_NAME);
|
|
947
|
-
for (const call of toolCalls)
|
|
984
|
+
for (const call of toolCalls) {
|
|
948
985
|
nudgedSkills.add(unquoteArg(call.arguments.name));
|
|
949
|
-
|
|
986
|
+
}
|
|
987
|
+
if (toolCalls.length) {
|
|
950
988
|
hlog('recovered skill-named call', { round });
|
|
989
|
+
}
|
|
951
990
|
}
|
|
952
991
|
if (!toolCalls.length) {
|
|
953
992
|
const replay = recovered.replay ? stripToolCallMarkup(recovered.replay) : '';
|
|
954
|
-
if (replay)
|
|
993
|
+
if (replay) {
|
|
955
994
|
yield { type: 'content', text: replay };
|
|
995
|
+
}
|
|
956
996
|
const spoken = recovered.contentText.trim();
|
|
957
997
|
if (enabled.length && !narrated && !replay && NARRATED_INTENT.test(spoken)) {
|
|
958
998
|
hlog('round narrated a tool call instead of making it', { round });
|
|
@@ -970,16 +1010,25 @@ export async function* completion(sdk, { modelId, acquireRound, model, agent, ct
|
|
|
970
1010
|
break;
|
|
971
1011
|
}
|
|
972
1012
|
hlog('round produced no answer', { round, mute });
|
|
973
|
-
if (mute++ < MAX_MUTE_ROUNDS)
|
|
1013
|
+
if (mute++ < MAX_MUTE_ROUNDS) {
|
|
974
1014
|
continue;
|
|
1015
|
+
}
|
|
975
1016
|
outcome = 'mute';
|
|
976
1017
|
break;
|
|
977
1018
|
}
|
|
978
1019
|
mute = 0;
|
|
979
1020
|
narrated = false;
|
|
980
|
-
const resolved = await resolveToolCalls(toolCalls,
|
|
981
|
-
|
|
1021
|
+
const resolved = await resolveToolCalls(toolCalls, {
|
|
1022
|
+
enabled,
|
|
1023
|
+
agentId: agent?.id ?? null,
|
|
1024
|
+
pipeline,
|
|
1025
|
+
skillNames: inContextSkills.map((skill) => skill.name),
|
|
1026
|
+
sandboxMode: agent?.sandboxMode === true,
|
|
1027
|
+
signal
|
|
1028
|
+
});
|
|
1029
|
+
if (signal?.aborted) {
|
|
982
1030
|
throw new AbortedError();
|
|
1031
|
+
}
|
|
983
1032
|
history = [
|
|
984
1033
|
...history,
|
|
985
1034
|
{
|
|
@@ -1062,7 +1111,8 @@ export async function* completion(sdk, { modelId, acquireRound, model, agent, ct
|
|
|
1062
1111
|
});
|
|
1063
1112
|
}
|
|
1064
1113
|
else if (tool) {
|
|
1065
|
-
execution = await executeCall(tool, args,
|
|
1114
|
+
execution = await executeCall(tool, args, {
|
|
1115
|
+
ctx: callCtx,
|
|
1066
1116
|
approve,
|
|
1067
1117
|
signal,
|
|
1068
1118
|
denied,
|
|
@@ -1103,21 +1153,8 @@ export async function* completion(sdk, { modelId, acquireRound, model, agent, ct
|
|
|
1103
1153
|
else if (tool?.name === WEB_SEARCH_TOOL_NAME && !rejection && !priorFailure) {
|
|
1104
1154
|
webSearches++;
|
|
1105
1155
|
}
|
|
1106
|
-
if (call.name === SKILL_TOOL_NAME
|
|
1107
|
-
output
|
|
1108
|
-
typeof output === 'object' &&
|
|
1109
|
-
'content' in output) {
|
|
1110
|
-
loadedSkills.add(skillName);
|
|
1111
|
-
if ('file' in output && typeof output.file === 'string') {
|
|
1112
|
-
const files = loadedSkillFiles.get(skillName) ?? new Set();
|
|
1113
|
-
files.add(output.file);
|
|
1114
|
-
loadedSkillFiles.set(skillName, files);
|
|
1115
|
-
}
|
|
1116
|
-
if (mainRequested)
|
|
1117
|
-
loadedThisTurn.add(skillName);
|
|
1118
|
-
else
|
|
1119
|
-
loadedFilesThisTurn.add(fileKey(skillName, unquoteArg(askedFile)));
|
|
1120
|
-
skillIcon = skillEmoji(skillName) ?? skillIcon;
|
|
1156
|
+
if (call.name === SKILL_TOOL_NAME) {
|
|
1157
|
+
recordSkillLoad(skillName, output, { mainRequested, askedFile });
|
|
1121
1158
|
}
|
|
1122
1159
|
if (!activity &&
|
|
1123
1160
|
!silent &&
|
|
@@ -1131,8 +1168,9 @@ export async function* completion(sdk, { modelId, acquireRound, model, agent, ct
|
|
|
1131
1168
|
decision: 'blocked'
|
|
1132
1169
|
};
|
|
1133
1170
|
}
|
|
1134
|
-
if (activity)
|
|
1171
|
+
if (activity) {
|
|
1135
1172
|
yield activity;
|
|
1173
|
+
}
|
|
1136
1174
|
if (!silent) {
|
|
1137
1175
|
yield {
|
|
1138
1176
|
type: 'tool-result',
|
|
@@ -1160,8 +1198,9 @@ export async function* completion(sdk, { modelId, acquireRound, model, agent, ct
|
|
|
1160
1198
|
blockedRepeats = 0;
|
|
1161
1199
|
}
|
|
1162
1200
|
history.push({ role: 'user', content: TOOL_CONTINUATION_NUDGE });
|
|
1163
|
-
if (blockedRepeats >= MAX_BLOCKED_REPEATS)
|
|
1201
|
+
if (blockedRepeats >= MAX_BLOCKED_REPEATS) {
|
|
1164
1202
|
break;
|
|
1203
|
+
}
|
|
1165
1204
|
if (cappedCalls === resolved.length) {
|
|
1166
1205
|
if (cappedRounds++ >= MAX_CAPPED_ROUNDS) {
|
|
1167
1206
|
outcome = 'search-capped';
|
|
@@ -1176,12 +1215,14 @@ export async function* completion(sdk, { modelId, acquireRound, model, agent, ct
|
|
|
1176
1215
|
yield* reportUnnamedWrites(said, landed);
|
|
1177
1216
|
const answered = metricsEvent(stats, runUsage());
|
|
1178
1217
|
runOutcome = 'done';
|
|
1179
|
-
if (answered)
|
|
1218
|
+
if (answered) {
|
|
1180
1219
|
yield answered;
|
|
1220
|
+
}
|
|
1181
1221
|
return;
|
|
1182
1222
|
}
|
|
1183
|
-
if (signal?.aborted)
|
|
1223
|
+
if (signal?.aborted) {
|
|
1184
1224
|
throw new AbortedError();
|
|
1225
|
+
}
|
|
1185
1226
|
const recovered = yield* runRecoveredRound(sdk, {
|
|
1186
1227
|
modelId,
|
|
1187
1228
|
acquireRound,
|
|
@@ -1196,8 +1237,9 @@ export async function* completion(sdk, { modelId, acquireRound, model, agent, ct
|
|
|
1196
1237
|
});
|
|
1197
1238
|
collectStats(stats, recovered.final.stats, recovered.final.stopReason);
|
|
1198
1239
|
const answer = recovered.replay ? stripToolCallMarkup(recovered.replay) : '';
|
|
1199
|
-
if (answer)
|
|
1240
|
+
if (answer) {
|
|
1200
1241
|
yield { type: 'content', text: answer };
|
|
1242
|
+
}
|
|
1201
1243
|
said = `${recovered.contentText}\n${answer}`;
|
|
1202
1244
|
if (!said.trim()) {
|
|
1203
1245
|
hlog('degenerate wrap-up', { outcome });
|
|
@@ -1211,13 +1253,18 @@ export async function* completion(sdk, { modelId, acquireRound, model, agent, ct
|
|
|
1211
1253
|
}
|
|
1212
1254
|
const metrics = metricsEvent(stats, runUsage());
|
|
1213
1255
|
runOutcome = 'done';
|
|
1214
|
-
if (metrics)
|
|
1256
|
+
if (metrics) {
|
|
1215
1257
|
yield metrics;
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
try {
|
|
1261
|
+
yield* runTurn();
|
|
1216
1262
|
}
|
|
1217
1263
|
catch (err) {
|
|
1218
1264
|
const written = writeReport(landed);
|
|
1219
|
-
if (written)
|
|
1265
|
+
if (written) {
|
|
1220
1266
|
yield { type: 'content', text: written };
|
|
1267
|
+
}
|
|
1221
1268
|
if (err instanceof AbortedError) {
|
|
1222
1269
|
runOutcome = 'aborted';
|
|
1223
1270
|
yield { type: 'aborted' };
|
|
@@ -1240,3 +1287,17 @@ export async function* completion(sdk, { modelId, acquireRound, model, agent, ct
|
|
|
1240
1287
|
});
|
|
1241
1288
|
}
|
|
1242
1289
|
}
|
|
1290
|
+
function toolDecision({ auto, skipAll, approved }) {
|
|
1291
|
+
if (auto)
|
|
1292
|
+
return 'auto';
|
|
1293
|
+
if (skipAll)
|
|
1294
|
+
return 'skip-all';
|
|
1295
|
+
return approved ? 'allowed' : 'denied';
|
|
1296
|
+
}
|
|
1297
|
+
function reasoningFlag(setting) {
|
|
1298
|
+
if (setting === 'enabled')
|
|
1299
|
+
return true;
|
|
1300
|
+
if (setting === 'disabled')
|
|
1301
|
+
return false;
|
|
1302
|
+
return undefined;
|
|
1303
|
+
}
|