@namzu/sdk 35.0.0 → 37.0.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 +218 -0
- package/README.md +68 -41
- package/dist/bridge/a2a/mapper.d.ts.map +1 -1
- package/dist/bridge/a2a/mapper.js +2 -0
- package/dist/bridge/a2a/mapper.js.map +1 -1
- package/dist/bridge/sse/mapper.d.ts.map +1 -1
- package/dist/bridge/sse/mapper.js +2 -0
- package/dist/bridge/sse/mapper.js.map +1 -1
- package/dist/compaction/extractor.d.ts +1 -1
- package/dist/compaction/extractor.d.ts.map +1 -1
- package/dist/compaction/extractor.js +15 -7
- package/dist/compaction/extractor.js.map +1 -1
- package/dist/compaction/manager.d.ts +2 -0
- package/dist/compaction/manager.d.ts.map +1 -1
- package/dist/compaction/manager.js +12 -1
- package/dist/compaction/manager.js.map +1 -1
- package/dist/compaction/verifier.d.ts.map +1 -1
- package/dist/compaction/verifier.js +82 -15
- package/dist/compaction/verifier.js.map +1 -1
- package/dist/contracts/schemas.d.ts +10 -10
- package/dist/eval/harness-verification.d.ts +63 -0
- package/dist/eval/harness-verification.d.ts.map +1 -0
- package/dist/eval/harness-verification.js +165 -0
- package/dist/eval/harness-verification.js.map +1 -0
- package/dist/eval/index.d.ts +2 -0
- package/dist/eval/index.d.ts.map +1 -1
- package/dist/eval/index.js +1 -0
- package/dist/eval/index.js.map +1 -1
- package/dist/execution/code-runtime/json-value.d.ts +10 -0
- package/dist/execution/code-runtime/json-value.d.ts.map +1 -0
- package/dist/execution/code-runtime/json-value.js +89 -0
- package/dist/execution/code-runtime/json-value.js.map +1 -0
- package/dist/execution/code-runtime/worker-program.d.ts +8 -0
- package/dist/execution/code-runtime/worker-program.d.ts.map +1 -0
- package/dist/execution/code-runtime/worker-program.js +240 -0
- package/dist/execution/code-runtime/worker-program.js.map +1 -0
- package/dist/execution/code-runtime/worker.d.ts +22 -0
- package/dist/execution/code-runtime/worker.d.ts.map +1 -1
- package/dist/execution/code-runtime/worker.js +148 -111
- package/dist/execution/code-runtime/worker.js.map +1 -1
- package/dist/manager/agent/lifecycle.d.ts +12 -0
- package/dist/manager/agent/lifecycle.d.ts.map +1 -1
- package/dist/manager/agent/lifecycle.js +306 -37
- package/dist/manager/agent/lifecycle.js.map +1 -1
- package/dist/manager/run/persistence.d.ts +2 -0
- package/dist/manager/run/persistence.d.ts.map +1 -1
- package/dist/manager/run/persistence.js +6 -0
- package/dist/manager/run/persistence.js.map +1 -1
- package/dist/provider/capabilities.d.ts +3 -1
- package/dist/provider/capabilities.d.ts.map +1 -1
- package/dist/provider/capabilities.js +13 -0
- package/dist/provider/capabilities.js.map +1 -1
- package/dist/provider/fallback.d.ts.map +1 -1
- package/dist/provider/fallback.js +2 -0
- package/dist/provider/fallback.js.map +1 -1
- package/dist/provider/token-budget.d.ts.map +1 -1
- package/dist/provider/token-budget.js +56 -8
- package/dist/provider/token-budget.js.map +1 -1
- package/dist/public-runtime.d.ts +5 -3
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +3 -2
- package/dist/public-runtime.js.map +1 -1
- package/dist/public-tools.d.ts +1 -1
- package/dist/public-tools.d.ts.map +1 -1
- package/dist/public-tools.js +1 -1
- package/dist/public-tools.js.map +1 -1
- package/dist/public-types.d.ts +1 -0
- package/dist/public-types.d.ts.map +1 -1
- package/dist/registry/tool/execute.d.ts +3 -0
- package/dist/registry/tool/execute.d.ts.map +1 -1
- package/dist/registry/tool/execute.js +11 -80
- package/dist/registry/tool/execute.js.map +1 -1
- package/dist/run/command-gate.d.ts.map +1 -1
- package/dist/run/command-gate.js +65 -12
- package/dist/run/command-gate.js.map +1 -1
- package/dist/run/index.d.ts +2 -0
- package/dist/run/index.d.ts.map +1 -1
- package/dist/run/index.js +1 -0
- package/dist/run/index.js.map +1 -1
- package/dist/run/memory-promoter.d.ts +3 -35
- package/dist/run/memory-promoter.d.ts.map +1 -1
- package/dist/run/memory-promoter.js +32 -40
- package/dist/run/memory-promoter.js.map +1 -1
- package/dist/run/memory-recall.d.ts +25 -0
- package/dist/run/memory-recall.d.ts.map +1 -0
- package/dist/run/memory-recall.js +228 -0
- package/dist/run/memory-recall.js.map +1 -0
- package/dist/run/reporter.d.ts.map +1 -1
- package/dist/run/reporter.js +1 -0
- package/dist/run/reporter.js.map +1 -1
- package/dist/run/token-budget.d.ts +2 -0
- package/dist/run/token-budget.d.ts.map +1 -1
- package/dist/run/token-budget.js +4 -0
- package/dist/run/token-budget.js.map +1 -1
- package/dist/run/workspace-fingerprint.d.ts +10 -3
- package/dist/run/workspace-fingerprint.d.ts.map +1 -1
- package/dist/run/workspace-fingerprint.js +17 -8
- package/dist/run/workspace-fingerprint.js.map +1 -1
- package/dist/runtime/query/checkpoint.d.ts +14 -0
- package/dist/runtime/query/checkpoint.d.ts.map +1 -1
- package/dist/runtime/query/checkpoint.js +82 -1
- package/dist/runtime/query/checkpoint.js.map +1 -1
- package/dist/runtime/query/executor.d.ts +6 -0
- package/dist/runtime/query/executor.d.ts.map +1 -1
- package/dist/runtime/query/executor.js +120 -24
- package/dist/runtime/query/executor.js.map +1 -1
- package/dist/runtime/query/index.d.ts +12 -8
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +55 -7
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/runtime/query/iteration/index.d.ts +13 -3
- package/dist/runtime/query/iteration/index.d.ts.map +1 -1
- package/dist/runtime/query/iteration/index.js +356 -42
- package/dist/runtime/query/iteration/index.js.map +1 -1
- package/dist/runtime/query/iteration/native-output.d.ts +10 -0
- package/dist/runtime/query/iteration/native-output.d.ts.map +1 -0
- package/dist/runtime/query/iteration/native-output.js +32 -0
- package/dist/runtime/query/iteration/native-output.js.map +1 -0
- package/dist/runtime/query/iteration/phases/advisory.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/advisory.js +18 -13
- package/dist/runtime/query/iteration/phases/advisory.js.map +1 -1
- package/dist/runtime/query/iteration/phases/compaction.d.ts +2 -0
- package/dist/runtime/query/iteration/phases/compaction.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/compaction.js +32 -11
- package/dist/runtime/query/iteration/phases/compaction.js.map +1 -1
- package/dist/runtime/query/iteration/phases/context.d.ts +11 -0
- package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/context.js.map +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.js +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
- package/dist/runtime/query/iteration/phases/working-memory.d.ts +1 -1
- package/dist/runtime/query/iteration/phases/working-memory.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/working-memory.js +23 -6
- package/dist/runtime/query/iteration/phases/working-memory.js.map +1 -1
- package/dist/runtime/query/iteration/stream-turn.d.ts.map +1 -1
- package/dist/runtime/query/iteration/stream-turn.js +12 -5
- package/dist/runtime/query/iteration/stream-turn.js.map +1 -1
- package/dist/runtime/query/prompt.d.ts.map +1 -1
- package/dist/runtime/query/prompt.js +14 -4
- package/dist/runtime/query/prompt.js.map +1 -1
- package/dist/runtime/query/steering.d.ts +6 -2
- package/dist/runtime/query/steering.d.ts.map +1 -1
- package/dist/runtime/query/steering.js +17 -2
- package/dist/runtime/query/steering.js.map +1 -1
- package/dist/runtime/query/tool-call-budget.d.ts +19 -0
- package/dist/runtime/query/tool-call-budget.d.ts.map +1 -0
- package/dist/runtime/query/tool-call-budget.js +110 -0
- package/dist/runtime/query/tool-call-budget.js.map +1 -0
- package/dist/runtime/query/tooling.d.ts +2 -0
- package/dist/runtime/query/tooling.d.ts.map +1 -1
- package/dist/runtime/query/tooling.js +4 -0
- package/dist/runtime/query/tooling.js.map +1 -1
- package/dist/sandbox/file-walk-program.d.ts +3 -0
- package/dist/sandbox/file-walk-program.d.ts.map +1 -0
- package/dist/sandbox/file-walk-program.js +94 -0
- package/dist/sandbox/file-walk-program.js.map +1 -0
- package/dist/sandbox/file-walk.d.ts +12 -0
- package/dist/sandbox/file-walk.d.ts.map +1 -0
- package/dist/sandbox/file-walk.js +429 -0
- package/dist/sandbox/file-walk.js.map +1 -0
- package/dist/sandbox/index.d.ts +2 -0
- package/dist/sandbox/index.d.ts.map +1 -1
- package/dist/sandbox/index.js +1 -0
- package/dist/sandbox/index.js.map +1 -1
- package/dist/sandbox/provider/local.d.ts.map +1 -1
- package/dist/sandbox/provider/local.js +9 -0
- package/dist/sandbox/provider/local.js.map +1 -1
- package/dist/scheduler/completion-inbox.d.ts +3 -2
- package/dist/scheduler/completion-inbox.d.ts.map +1 -1
- package/dist/scheduler/completion-inbox.js +29 -15
- package/dist/scheduler/completion-inbox.js.map +1 -1
- package/dist/scheduler/local.d.ts.map +1 -1
- package/dist/scheduler/local.js +1 -0
- package/dist/scheduler/local.js.map +1 -1
- package/dist/session/handoff/capacity.d.ts +2 -2
- package/dist/session/handoff/capacity.d.ts.map +1 -1
- package/dist/session/handoff/capacity.js +3 -2
- package/dist/session/handoff/capacity.js.map +1 -1
- package/dist/store/memory/disk.d.ts +6 -2
- package/dist/store/memory/disk.d.ts.map +1 -1
- package/dist/store/memory/disk.js +42 -25
- package/dist/store/memory/disk.js.map +1 -1
- package/dist/store/memory/index.d.ts +4 -0
- package/dist/store/memory/index.d.ts.map +1 -1
- package/dist/store/memory/index.js +55 -19
- package/dist/store/memory/index.js.map +1 -1
- package/dist/store/memory/memory.d.ts +3 -2
- package/dist/store/memory/memory.d.ts.map +1 -1
- package/dist/store/memory/memory.js +11 -2
- package/dist/store/memory/memory.js.map +1 -1
- package/dist/store/memory/operation-lock.d.ts +11 -0
- package/dist/store/memory/operation-lock.d.ts.map +1 -0
- package/dist/store/memory/operation-lock.js +94 -0
- package/dist/store/memory/operation-lock.js.map +1 -0
- package/dist/tools/builtins/bash.d.ts.map +1 -1
- package/dist/tools/builtins/bash.js +215 -59
- package/dist/tools/builtins/bash.js.map +1 -1
- package/dist/tools/builtins/computer-use.d.ts.map +1 -1
- package/dist/tools/builtins/computer-use.js +60 -10
- package/dist/tools/builtins/computer-use.js.map +1 -1
- package/dist/tools/builtins/glob.d.ts +2 -1
- package/dist/tools/builtins/glob.d.ts.map +1 -1
- package/dist/tools/builtins/glob.js +95 -103
- package/dist/tools/builtins/glob.js.map +1 -1
- package/dist/tools/builtins/grep.d.ts.map +1 -1
- package/dist/tools/builtins/grep.js +155 -111
- package/dist/tools/builtins/grep.js.map +1 -1
- package/dist/tools/builtins/ls.js +2 -2
- package/dist/tools/builtins/ls.js.map +1 -1
- package/dist/tools/builtins/run-code.d.ts +6 -0
- package/dist/tools/builtins/run-code.d.ts.map +1 -1
- package/dist/tools/builtins/run-code.js +15 -4
- package/dist/tools/builtins/run-code.js.map +1 -1
- package/dist/tools/builtins/search-tools.d.ts.map +1 -1
- package/dist/tools/builtins/search-tools.js +14 -2
- package/dist/tools/builtins/search-tools.js.map +1 -1
- package/dist/tools/defineTool.d.ts +2 -0
- package/dist/tools/defineTool.d.ts.map +1 -1
- package/dist/tools/defineTool.js +3 -0
- package/dist/tools/defineTool.js.map +1 -1
- package/dist/tools/memory/delete.d.ts +4 -0
- package/dist/tools/memory/delete.d.ts.map +1 -0
- package/dist/tools/memory/delete.js +26 -0
- package/dist/tools/memory/delete.js.map +1 -0
- package/dist/tools/memory/index.d.ts +2 -0
- package/dist/tools/memory/index.d.ts.map +1 -1
- package/dist/tools/memory/index.js +6 -0
- package/dist/tools/memory/index.js.map +1 -1
- package/dist/tools/memory/save.d.ts.map +1 -1
- package/dist/tools/memory/save.js +3 -2
- package/dist/tools/memory/save.js.map +1 -1
- package/dist/tools/memory/search.d.ts.map +1 -1
- package/dist/tools/memory/search.js +12 -5
- package/dist/tools/memory/search.js.map +1 -1
- package/dist/tools/memory/update.d.ts +4 -0
- package/dist/tools/memory/update.d.ts.map +1 -0
- package/dist/tools/memory/update.js +47 -0
- package/dist/tools/memory/update.js.map +1 -0
- package/dist/types/agent/scheduler.d.ts +5 -0
- package/dist/types/agent/scheduler.d.ts.map +1 -1
- package/dist/types/agent/task.d.ts +10 -0
- package/dist/types/agent/task.d.ts.map +1 -1
- package/dist/types/computer-use/index.d.ts +6 -0
- package/dist/types/computer-use/index.d.ts.map +1 -1
- package/dist/types/computer-use/index.js.map +1 -1
- package/dist/types/errors/catalog.js +1 -1
- package/dist/types/errors/catalog.js.map +1 -1
- package/dist/types/hitl/index.d.ts +11 -1
- package/dist/types/hitl/index.d.ts.map +1 -1
- package/dist/types/hitl/index.js.map +1 -1
- package/dist/types/memory/index.d.ts +14 -1
- package/dist/types/memory/index.d.ts.map +1 -1
- package/dist/types/project/entity.d.ts +1 -0
- package/dist/types/project/entity.d.ts.map +1 -1
- package/dist/types/provider/config.d.ts +2 -0
- package/dist/types/provider/config.d.ts.map +1 -1
- package/dist/types/provider/model.d.ts +4 -0
- package/dist/types/provider/model.d.ts.map +1 -1
- package/dist/types/run/answer-review.d.ts +2 -0
- package/dist/types/run/answer-review.d.ts.map +1 -1
- package/dist/types/run/events.d.ts +9 -0
- package/dist/types/run/events.d.ts.map +1 -1
- package/dist/types/run/events.js.map +1 -1
- package/dist/types/run/prepare-step.d.ts +19 -1
- package/dist/types/run/prepare-step.d.ts.map +1 -1
- package/dist/types/sandbox/index.d.ts +20 -0
- package/dist/types/sandbox/index.d.ts.map +1 -1
- package/dist/types/sandbox/index.js.map +1 -1
- package/dist/types/structured-output/index.d.ts +8 -2
- package/dist/types/structured-output/index.d.ts.map +1 -1
- package/dist/types/tool/index.d.ts +15 -0
- package/dist/types/tool/index.d.ts.map +1 -1
- package/dist/types/tool/index.js.map +1 -1
- package/dist/utils/json-snapshot.d.ts +3 -0
- package/dist/utils/json-snapshot.d.ts.map +1 -0
- package/dist/utils/json-snapshot.js +79 -0
- package/dist/utils/json-snapshot.js.map +1 -0
- package/package.json +8 -1
- package/src/bridge/a2a/mapper.ts +2 -0
- package/src/bridge/sse/mapper.ts +2 -0
- package/src/compaction/extractor.ts +21 -8
- package/src/compaction/manager.ts +11 -1
- package/src/compaction/verifier.ts +80 -18
- package/src/eval/harness-verification.ts +270 -0
- package/src/eval/index.ts +10 -0
- package/src/execution/code-runtime/json-value.ts +82 -0
- package/src/execution/code-runtime/worker-program.ts +239 -0
- package/src/execution/code-runtime/worker.ts +164 -111
- package/src/manager/agent/lifecycle.ts +340 -45
- package/src/manager/run/persistence.ts +7 -0
- package/src/provider/capabilities.ts +25 -1
- package/src/provider/fallback.ts +2 -0
- package/src/provider/token-budget.ts +52 -8
- package/src/public-runtime.ts +6 -1
- package/src/public-tools.ts +5 -1
- package/src/public-types.ts +1 -0
- package/src/registry/tool/execute.ts +17 -79
- package/src/run/command-gate.ts +61 -13
- package/src/run/index.ts +2 -0
- package/src/run/memory-promoter.ts +32 -40
- package/src/run/memory-recall.ts +254 -0
- package/src/run/reporter.ts +1 -0
- package/src/run/token-budget.ts +4 -0
- package/src/run/workspace-fingerprint.ts +17 -8
- package/src/runtime/query/checkpoint.ts +96 -2
- package/src/runtime/query/executor.ts +131 -28
- package/src/runtime/query/index.ts +81 -16
- package/src/runtime/query/iteration/index.ts +406 -53
- package/src/runtime/query/iteration/native-output.ts +35 -0
- package/src/runtime/query/iteration/phases/advisory.ts +21 -11
- package/src/runtime/query/iteration/phases/compaction.ts +36 -14
- package/src/runtime/query/iteration/phases/context.ts +11 -0
- package/src/runtime/query/iteration/phases/tool-review.ts +5 -1
- package/src/runtime/query/iteration/phases/working-memory.ts +23 -5
- package/src/runtime/query/iteration/stream-turn.ts +11 -5
- package/src/runtime/query/prompt.ts +21 -4
- package/src/runtime/query/steering.ts +19 -2
- package/src/runtime/query/tool-call-budget.ts +115 -0
- package/src/runtime/query/tooling.ts +6 -0
- package/src/sandbox/file-walk-program.ts +93 -0
- package/src/sandbox/file-walk.ts +463 -0
- package/src/sandbox/index.ts +2 -0
- package/src/sandbox/provider/local.ts +13 -0
- package/src/scheduler/completion-inbox.ts +29 -19
- package/src/scheduler/local.ts +1 -0
- package/src/session/handoff/capacity.ts +7 -3
- package/src/store/memory/disk.ts +52 -30
- package/src/store/memory/index.ts +75 -27
- package/src/store/memory/memory.ts +18 -6
- package/src/store/memory/operation-lock.ts +99 -0
- package/src/tools/builtins/bash.ts +230 -58
- package/src/tools/builtins/computer-use.ts +61 -7
- package/src/tools/builtins/glob.ts +104 -122
- package/src/tools/builtins/grep.ts +166 -132
- package/src/tools/builtins/ls.ts +2 -2
- package/src/tools/builtins/run-code.ts +24 -5
- package/src/tools/builtins/search-tools.ts +18 -3
- package/src/tools/defineTool.ts +5 -0
- package/src/tools/memory/delete.ts +29 -0
- package/src/tools/memory/index.ts +6 -0
- package/src/tools/memory/save.ts +4 -2
- package/src/tools/memory/search.ts +12 -5
- package/src/tools/memory/update.ts +50 -0
- package/src/types/agent/scheduler.ts +6 -0
- package/src/types/agent/task.ts +13 -0
- package/src/types/computer-use/index.ts +6 -0
- package/src/types/errors/catalog.ts +1 -1
- package/src/types/hitl/index.ts +11 -1
- package/src/types/memory/index.ts +16 -1
- package/src/types/project/entity.ts +1 -0
- package/src/types/provider/config.ts +2 -0
- package/src/types/provider/model.ts +4 -0
- package/src/types/run/answer-review.ts +2 -0
- package/src/types/run/events.ts +10 -0
- package/src/types/run/prepare-step.ts +19 -1
- package/src/types/sandbox/index.ts +21 -0
- package/src/types/structured-output/index.ts +15 -2
- package/src/types/tool/index.ts +16 -0
- package/src/utils/json-snapshot.ts +76 -0
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { spawn } from 'node:child_process'
|
|
2
|
+
import { StringDecoder } from 'node:string_decoder'
|
|
3
3
|
import { z } from 'zod'
|
|
4
|
+
import { SANDBOX_KILL_GRACE_MS } from '../../constants/sandbox/index.js'
|
|
4
5
|
import { DANGEROUS_PATTERNS } from '../../constants/tools/index.js'
|
|
6
|
+
import { killTree } from '../../process/kill-tree.js'
|
|
7
|
+
import { subscribeToAbort } from '../../utils/abort.js'
|
|
5
8
|
import { defineTool } from '../defineTool.js'
|
|
6
9
|
import { scrubInheritedEnv } from '../env-scrub.js'
|
|
7
10
|
|
|
8
|
-
const execAsync = promisify(exec)
|
|
9
11
|
// Namzu owns its own bash timeout knob — `NAMZU_BASH_TIMEOUT_MS`.
|
|
10
12
|
// The Vandal fallback (`VANDAL_NAMZU_TIMEOUT_MS`) lived here as a
|
|
11
13
|
// historical bridge while Namzu was carved out of the Vandal repo,
|
|
@@ -67,25 +69,205 @@ const inputSchema = z.object({
|
|
|
67
69
|
|
|
68
70
|
type BashInput = z.infer<typeof inputSchema>
|
|
69
71
|
|
|
72
|
+
const MAX_SHELL_PROGRESS_CHARS = 160
|
|
73
|
+
|
|
74
|
+
/** Keep a bounded tail even when a process never writes a newline. */
|
|
75
|
+
function appendProgressTail(previous: string, chunk: string, start: number, end: number): string {
|
|
76
|
+
return (previous + chunk.slice(Math.max(start, end - MAX_SHELL_PROGRESS_CHARS), end)).slice(
|
|
77
|
+
-MAX_SHELL_PROGRESS_CHARS,
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Clipping a UTF-16 string must not display half of a surrogate pair. */
|
|
82
|
+
function progressLine(value: string): string {
|
|
83
|
+
let line = value.trim()
|
|
84
|
+
const first = line.charCodeAt(0)
|
|
85
|
+
if (first >= 0xdc00 && first <= 0xdfff) line = line.slice(1)
|
|
86
|
+
const last = line.charCodeAt(line.length - 1)
|
|
87
|
+
if (last >= 0xd800 && last <= 0xdbff) line = line.slice(0, -1)
|
|
88
|
+
return line
|
|
89
|
+
}
|
|
90
|
+
|
|
70
91
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
* replaces it as the next arrives, so sending a whole chunk sends a wall
|
|
75
|
-
* of text into a slot that shows one line of it. A chunk usually ends
|
|
76
|
-
* mid-line and usually ends with a newline, so the last NON-EMPTY line is
|
|
77
|
-
* the most recent complete thing the command actually said.
|
|
78
|
-
*
|
|
79
|
-
* Progress is capped rather than truncated with an ellipsis: this is
|
|
80
|
-
* glanced at, and a marker in a line nobody reads to the end is noise.
|
|
92
|
+
* One latest line per stream, independent of transport chunk boundaries.
|
|
93
|
+
* Reports stay synchronous: the executor owns coalescing and backpressure.
|
|
94
|
+
* This projection adds neither an output log nor a queue of pending reports.
|
|
81
95
|
*/
|
|
82
|
-
function
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
96
|
+
function shellProgress(report?: (message: string) => void) {
|
|
97
|
+
if (!report) return undefined
|
|
98
|
+
const partial = { stdout: '', stderr: '' }
|
|
99
|
+
let lastMessage = ''
|
|
100
|
+
return ({ stream, data }: { stream: 'stdout' | 'stderr'; data: string }): void => {
|
|
101
|
+
let line = partial[stream]
|
|
102
|
+
let latest = ''
|
|
103
|
+
let start = 0
|
|
104
|
+
// Scan delimiters without allocating an array for arbitrarily chatty output.
|
|
105
|
+
for (const match of data.matchAll(/[\r\n]/g)) {
|
|
106
|
+
line = appendProgressTail(line, data, start, match.index)
|
|
107
|
+
latest = progressLine(line) || latest
|
|
108
|
+
line = ''
|
|
109
|
+
start = match.index + 1
|
|
110
|
+
}
|
|
111
|
+
line = appendProgressTail(line, data, start, data.length)
|
|
112
|
+
partial[stream] = line
|
|
113
|
+
const message = progressLine(line) || latest
|
|
114
|
+
if (!message || message === lastMessage) return
|
|
115
|
+
lastMessage = message
|
|
116
|
+
try {
|
|
117
|
+
report(message)
|
|
118
|
+
} catch {
|
|
119
|
+
// A diagnostic observer cannot break the process output reader.
|
|
120
|
+
}
|
|
87
121
|
}
|
|
88
|
-
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Keep the shell's process group until inherited pipes close. Node's exec
|
|
126
|
+
* timeout/AbortSignal kills only the wrapper and closes its pipes immediately,
|
|
127
|
+
* leaving the command and its descendants running after the promise settles.
|
|
128
|
+
*/
|
|
129
|
+
function execHostShell(
|
|
130
|
+
command: string,
|
|
131
|
+
options: {
|
|
132
|
+
cwd: string
|
|
133
|
+
env: NodeJS.ProcessEnv
|
|
134
|
+
timeout: number
|
|
135
|
+
maxBuffer: number
|
|
136
|
+
signal?: AbortSignal
|
|
137
|
+
onOutput?: ReturnType<typeof shellProgress>
|
|
138
|
+
},
|
|
139
|
+
): Promise<{ stdout: string; stderr: string }> {
|
|
140
|
+
options.signal?.throwIfAborted()
|
|
141
|
+
return new Promise((resolve, reject) => {
|
|
142
|
+
const child = spawn(command, {
|
|
143
|
+
cwd: options.cwd,
|
|
144
|
+
env: options.env,
|
|
145
|
+
shell: true,
|
|
146
|
+
// killTree's negative PID must never target the caller's own group.
|
|
147
|
+
detached: process.platform !== 'win32',
|
|
148
|
+
})
|
|
149
|
+
const captures = {
|
|
150
|
+
stdout: {
|
|
151
|
+
chunks: [] as Buffer[],
|
|
152
|
+
bytes: 0,
|
|
153
|
+
truncated: false,
|
|
154
|
+
decoder: new StringDecoder('utf8'),
|
|
155
|
+
},
|
|
156
|
+
stderr: {
|
|
157
|
+
chunks: [] as Buffer[],
|
|
158
|
+
bytes: 0,
|
|
159
|
+
truncated: false,
|
|
160
|
+
decoder: new StringDecoder('utf8'),
|
|
161
|
+
},
|
|
162
|
+
}
|
|
163
|
+
let cause: 'caller' | 'timeout' | 'maxBuffer' | undefined
|
|
164
|
+
let failure: (Error & { code?: string | number }) | undefined
|
|
165
|
+
let escalation: ReturnType<typeof setTimeout> | undefined
|
|
166
|
+
let disposeAbort: (() => void) | undefined
|
|
167
|
+
let closed = false
|
|
168
|
+
const cancel = (origin: NonNullable<typeof cause>) => {
|
|
169
|
+
if (closed || cause !== undefined) return
|
|
170
|
+
cause = origin
|
|
171
|
+
escalation = setTimeout(() => {
|
|
172
|
+
escalation = undefined
|
|
173
|
+
killTree(child, 'SIGKILL')
|
|
174
|
+
// A descendant can deliberately start a separate session. It is
|
|
175
|
+
// outside this group, but its inherited pipes must not hold the
|
|
176
|
+
// cancelled call forever. Keep what was captured during grace.
|
|
177
|
+
child.stdin?.destroy()
|
|
178
|
+
child.stdout?.destroy()
|
|
179
|
+
child.stderr?.destroy()
|
|
180
|
+
}, SANDBOX_KILL_GRACE_MS)
|
|
181
|
+
escalation.unref?.()
|
|
182
|
+
killTree(child, 'SIGTERM')
|
|
183
|
+
}
|
|
184
|
+
const capture = (stream: 'stdout' | 'stderr', chunk: Buffer) => {
|
|
185
|
+
const state = captures[stream]
|
|
186
|
+
const kept = Math.min(chunk.length, options.maxBuffer - state.bytes)
|
|
187
|
+
if (kept > 0) {
|
|
188
|
+
state.chunks.push(Buffer.from(chunk.subarray(0, kept)))
|
|
189
|
+
state.bytes += kept
|
|
190
|
+
}
|
|
191
|
+
if (kept < chunk.length) {
|
|
192
|
+
state.truncated = true
|
|
193
|
+
if (cause === undefined) {
|
|
194
|
+
failure = Object.assign(new RangeError(`${stream} maxBuffer length exceeded`), {
|
|
195
|
+
code: 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER',
|
|
196
|
+
})
|
|
197
|
+
cancel('maxBuffer')
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (options.onOutput) {
|
|
201
|
+
const data = state.decoder.write(chunk)
|
|
202
|
+
if (data) options.onOutput({ stream, data })
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
const onStdout = (chunk: Buffer) => capture('stdout', chunk)
|
|
206
|
+
const onStderr = (chunk: Buffer) => capture('stderr', chunk)
|
|
207
|
+
child.stdout?.on('data', onStdout)
|
|
208
|
+
child.stderr?.on('data', onStderr)
|
|
209
|
+
child.once('error', (error: NodeJS.ErrnoException) => {
|
|
210
|
+
failure ??= error
|
|
211
|
+
})
|
|
212
|
+
child.once('close', (code, signal) => {
|
|
213
|
+
closed = true
|
|
214
|
+
disposeAbort?.()
|
|
215
|
+
clearTimeout(deadline)
|
|
216
|
+
if (escalation !== undefined) {
|
|
217
|
+
clearTimeout(escalation)
|
|
218
|
+
// Pipes closing can precede a descendant which closed its copies.
|
|
219
|
+
// Force the owned group now instead of retaining its PID in a timer.
|
|
220
|
+
killTree(child, 'SIGKILL')
|
|
221
|
+
}
|
|
222
|
+
child.stdout?.off('data', onStdout)
|
|
223
|
+
child.stderr?.off('data', onStderr)
|
|
224
|
+
for (const stream of ['stdout', 'stderr'] as const) {
|
|
225
|
+
const data = captures[stream].decoder.end()
|
|
226
|
+
if (data) options.onOutput?.({ stream, data })
|
|
227
|
+
}
|
|
228
|
+
const decodeCapture = (stream: 'stdout' | 'stderr') => {
|
|
229
|
+
const state = captures[stream]
|
|
230
|
+
const bytes = Buffer.concat(state.chunks, state.bytes)
|
|
231
|
+
// Do not flush an incomplete UTF-8 character cut by our byte cap.
|
|
232
|
+
return state.truncated ? new StringDecoder('utf8').write(bytes) : bytes.toString('utf8')
|
|
233
|
+
}
|
|
234
|
+
const stdout = decodeCapture('stdout')
|
|
235
|
+
const stderr = decodeCapture('stderr')
|
|
236
|
+
if (!failure && cause === undefined && code === 0 && signal === null) {
|
|
237
|
+
resolve({ stdout, stderr })
|
|
238
|
+
return
|
|
239
|
+
}
|
|
240
|
+
const error =
|
|
241
|
+
failure ??
|
|
242
|
+
(cause === 'caller'
|
|
243
|
+
? Object.assign(
|
|
244
|
+
new Error('The operation was aborted', { cause: options.signal?.reason }),
|
|
245
|
+
{
|
|
246
|
+
name: 'AbortError',
|
|
247
|
+
code: 'ABORT_ERR',
|
|
248
|
+
},
|
|
249
|
+
)
|
|
250
|
+
: new Error(`Command failed: ${command}\n${stderr}`))
|
|
251
|
+
reject(
|
|
252
|
+
Object.assign(error, {
|
|
253
|
+
stdout,
|
|
254
|
+
stderr,
|
|
255
|
+
stdoutTruncated: captures.stdout.truncated,
|
|
256
|
+
stderrTruncated: captures.stderr.truncated,
|
|
257
|
+
code: failure?.code ?? (cause === 'caller' ? 'ABORT_ERR' : code),
|
|
258
|
+
killed: cause !== undefined,
|
|
259
|
+
signal,
|
|
260
|
+
timedOut: cause === 'timeout',
|
|
261
|
+
}),
|
|
262
|
+
)
|
|
263
|
+
})
|
|
264
|
+
const deadline = setTimeout(() => cancel('timeout'), options.timeout)
|
|
265
|
+
deadline.unref?.()
|
|
266
|
+
if (options.signal) {
|
|
267
|
+
disposeAbort = subscribeToAbort(options.signal, () => cancel('caller'))
|
|
268
|
+
if (options.signal.aborted) cancel('caller')
|
|
269
|
+
}
|
|
270
|
+
})
|
|
89
271
|
}
|
|
90
272
|
|
|
91
273
|
function isDangerousCommand(command: string): boolean {
|
|
@@ -192,6 +374,7 @@ export const BashTool = defineTool({
|
|
|
192
374
|
// sandbox can be added later as an explicit
|
|
193
375
|
// `SandboxExecOptions.workspaceRelativeCwd` field; the bash
|
|
194
376
|
// builtin doesn't have that requirement today.
|
|
377
|
+
const onOutput = shellProgress(context.report)
|
|
195
378
|
if (context.sandbox) {
|
|
196
379
|
const result = await context.sandbox.exec('/bin/sh', ['-c', input.command], {
|
|
197
380
|
timeout: input.timeout,
|
|
@@ -206,22 +389,9 @@ export const BashTool = defineTool({
|
|
|
206
389
|
// durable transcript — so this is a progress signal, not a
|
|
207
390
|
// second copy of the output. `result.stdout` remains the
|
|
208
391
|
// answer the model is given.
|
|
209
|
-
onOutput
|
|
210
|
-
? ({ data }) => {
|
|
211
|
-
const line = lastNonEmptyLine(data)
|
|
212
|
-
if (line) context.report?.(line)
|
|
213
|
-
}
|
|
214
|
-
: undefined,
|
|
392
|
+
onOutput,
|
|
215
393
|
})
|
|
216
394
|
|
|
217
|
-
if (result.timedOut) {
|
|
218
|
-
return {
|
|
219
|
-
success: false,
|
|
220
|
-
output: '',
|
|
221
|
-
error: `Command timed out after ${input.timeout}ms`,
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
395
|
// The sandbox reports when IT clipped a stream. Dropping those
|
|
226
396
|
// flags meant the model saw a complete-looking result that had
|
|
227
397
|
// silently lost its tail — and the kernel's own convention is
|
|
@@ -235,41 +405,32 @@ export const BashTool = defineTool({
|
|
|
235
405
|
result.stdout ? `STDOUT:\n${result.stdout}` : '',
|
|
236
406
|
result.stderr ? `STDERR:\n${result.stderr}` : '',
|
|
237
407
|
clipped.length > 0
|
|
238
|
-
? `[${clipped.join(' and ')} was truncated by the sandbox output cap
|
|
408
|
+
? `[${clipped.join(' and ')} was truncated by the sandbox output cap. The omitted output is unavailable in this result. Use a saved artifact or a read-only observation; do not repeat a state-changing action to recover its output.]`
|
|
239
409
|
: '',
|
|
240
410
|
]
|
|
241
411
|
.filter(Boolean)
|
|
242
412
|
.join('\n\n')
|
|
243
413
|
|
|
244
414
|
return {
|
|
245
|
-
success: result.exitCode === 0,
|
|
415
|
+
success: !result.timedOut && result.exitCode === 0,
|
|
246
416
|
output: output || '(no output)',
|
|
247
417
|
data: {
|
|
248
418
|
exitCode: result.exitCode,
|
|
249
419
|
sandboxed: true,
|
|
420
|
+
timedOut: result.timedOut,
|
|
250
421
|
stdoutTruncated: result.stdoutTruncated ?? false,
|
|
251
422
|
stderrTruncated: result.stderrTruncated ?? false,
|
|
252
423
|
},
|
|
253
|
-
error: result.
|
|
424
|
+
error: result.timedOut
|
|
425
|
+
? `Command timed out after ${input.timeout}ms. Any captured output before the deadline is above.`
|
|
426
|
+
: result.exitCode !== 0
|
|
427
|
+
? `Command exited with code ${result.exitCode}`
|
|
428
|
+
: undefined,
|
|
254
429
|
}
|
|
255
430
|
}
|
|
256
431
|
|
|
257
|
-
//
|
|
258
|
-
// a
|
|
259
|
-
// and the executor's deadline could only ever DETACH from the tool
|
|
260
|
-
// rather than end the work it started.
|
|
261
|
-
// `exec` REJECTS on a non-zero exit, on its own timeout, and on a
|
|
262
|
-
// kill — and the rejection carries `stdout`, `stderr`, `code` and
|
|
263
|
-
// `killed`. Letting it propagate threw all of that away: the registry
|
|
264
|
-
// turned the throw into a structured failure, so the model was told a
|
|
265
|
-
// command failed and not one word about how.
|
|
266
|
-
//
|
|
267
|
-
// That is the common case, not an edge one. A failing test run and a
|
|
268
|
-
// failing build are the two things an agent runs bash for most, and
|
|
269
|
-
// both exit non-zero WITH the output that explains why. The sandbox
|
|
270
|
-
// branch above already reports all of it; this branch did not, so the
|
|
271
|
-
// same command told the model two different amounts depending on where
|
|
272
|
-
// it happened to run.
|
|
432
|
+
// The owned runner retains stdout/stderr on non-zero exit and timeout,
|
|
433
|
+
// so a failed command still returns the evidence explaining its failure.
|
|
273
434
|
// The inherited half is scrubbed; `context.env` is not. Inheritance is
|
|
274
435
|
// implicit — nobody decided this command should see `process.env` — while
|
|
275
436
|
// a `context.env` key is one a host wrote on purpose. See
|
|
@@ -278,14 +439,14 @@ export const BashTool = defineTool({
|
|
|
278
439
|
const inherited = scrubInheritedEnv()
|
|
279
440
|
|
|
280
441
|
try {
|
|
281
|
-
const { stdout, stderr } = await
|
|
442
|
+
const { stdout, stderr } = await execHostShell(input.command, {
|
|
282
443
|
cwd: context.workingDirectory,
|
|
283
444
|
timeout: input.timeout,
|
|
284
445
|
env: { ...inherited.env, ...context.env },
|
|
285
446
|
maxBuffer: DEFAULT_BASH_MAX_BUFFER_BYTES,
|
|
286
447
|
signal: context.abortSignal,
|
|
448
|
+
onOutput,
|
|
287
449
|
})
|
|
288
|
-
|
|
289
450
|
return {
|
|
290
451
|
success: true,
|
|
291
452
|
output: formatShellOutput(stdout, stderr) || '(no output)',
|
|
@@ -295,25 +456,34 @@ export const BashTool = defineTool({
|
|
|
295
456
|
const failure = err as NodeJS.ErrnoException & {
|
|
296
457
|
stdout?: string
|
|
297
458
|
stderr?: string
|
|
459
|
+
stdoutTruncated?: boolean
|
|
460
|
+
stderrTruncated?: boolean
|
|
298
461
|
code?: number | string
|
|
299
462
|
killed?: boolean
|
|
300
463
|
signal?: string
|
|
464
|
+
timedOut?: boolean
|
|
301
465
|
}
|
|
302
466
|
|
|
303
467
|
// A caller-owned Stop is the caller's, not a command failure.
|
|
304
468
|
if (context.abortSignal?.aborted) throw err
|
|
305
469
|
|
|
306
|
-
//
|
|
307
|
-
//
|
|
308
|
-
|
|
309
|
-
const timedOut = failure.killed === true && failure.signal === 'SIGTERM'
|
|
470
|
+
// A maxBuffer stop or an ordinary signal is not a deadline. The
|
|
471
|
+
// runner latches the first cancellation cause before signalling.
|
|
472
|
+
const timedOut = failure.timedOut === true
|
|
310
473
|
const exitCode = typeof failure.code === 'number' ? failure.code : undefined
|
|
474
|
+
const clipped = [
|
|
475
|
+
failure.stdoutTruncated ? 'stdout' : '',
|
|
476
|
+
failure.stderrTruncated ? 'stderr' : '',
|
|
477
|
+
].filter(Boolean)
|
|
311
478
|
// Only on the failure path. A successful command did not need to know,
|
|
312
479
|
// and appending this to every result would make the common case noisy
|
|
313
480
|
// to buy nothing. A failing one is exactly where "authentication
|
|
314
481
|
// failed" has to be distinguishable from "the variable was withheld".
|
|
315
482
|
const output = [
|
|
316
483
|
formatShellOutput(failure.stdout, failure.stderr),
|
|
484
|
+
clipped.length > 0
|
|
485
|
+
? `[${clipped.join(' and ')} ${clipped.length === 1 ? 'was' : 'were'} truncated by the host output cap. The omitted output is unavailable in this result.]`
|
|
486
|
+
: '',
|
|
317
487
|
describeWithheldEnv(inherited.dropped),
|
|
318
488
|
]
|
|
319
489
|
.filter(Boolean)
|
|
@@ -325,6 +495,8 @@ export const BashTool = defineTool({
|
|
|
325
495
|
data: {
|
|
326
496
|
...(exitCode !== undefined ? { exitCode } : {}),
|
|
327
497
|
timedOut,
|
|
498
|
+
stdoutTruncated: failure.stdoutTruncated ?? false,
|
|
499
|
+
stderrTruncated: failure.stderrTruncated ?? false,
|
|
328
500
|
...(failure.signal ? { signal: failure.signal } : {}),
|
|
329
501
|
},
|
|
330
502
|
error: timedOut
|
|
@@ -63,7 +63,7 @@ const pointModelInputSchema = {
|
|
|
63
63
|
additionalProperties: false,
|
|
64
64
|
} as const
|
|
65
65
|
|
|
66
|
-
const modelInputSchema
|
|
66
|
+
const modelInputSchema = {
|
|
67
67
|
type: 'object',
|
|
68
68
|
properties: {
|
|
69
69
|
type: {
|
|
@@ -136,16 +136,17 @@ function requiredCapability(type: ComputerUseAction['type']): keyof ComputerUseC
|
|
|
136
136
|
|
|
137
137
|
function buildDescription(host: ComputerUseHost): string {
|
|
138
138
|
const caps = host.capabilities
|
|
139
|
-
const available
|
|
140
|
-
if (caps.screenshot) available.push('screenshot')
|
|
141
|
-
if (caps.cursorPosition) available.push('cursor_position')
|
|
142
|
-
if (caps.mouse) available.push('mouse_move, mouse_click, mouse_drag, scroll')
|
|
143
|
-
if (caps.keyboard) available.push('type_text, key')
|
|
139
|
+
const available = availableActions(caps)
|
|
144
140
|
const unavailable: string[] = []
|
|
145
141
|
if (!caps.screenshot) unavailable.push('screenshot')
|
|
146
142
|
if (!caps.cursorPosition) unavailable.push('cursor_position')
|
|
147
143
|
if (!caps.mouse) unavailable.push('mouse')
|
|
148
144
|
if (!caps.keyboard) unavailable.push('keyboard')
|
|
145
|
+
if (caps.supportedActions) {
|
|
146
|
+
for (const action of actionSchema.options.map((option) => option.shape.type.value)) {
|
|
147
|
+
if (!available.includes(action)) unavailable.push(action)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
149
150
|
|
|
150
151
|
const lines = [
|
|
151
152
|
`Controls the user's desktop on a ${caps.displayServer} host. Use to take screenshots and drive mouse/keyboard input for GUI tasks.`,
|
|
@@ -161,9 +162,42 @@ function buildDescription(host: ComputerUseHost): string {
|
|
|
161
162
|
lines.push(
|
|
162
163
|
'Coordinates are in logical pixels from the top-left of the primary display. Call getDisplayGeometry through screenshot output before clicking to confirm bounds.',
|
|
163
164
|
)
|
|
165
|
+
if (caps.mouseClickButtons && available.includes('mouse_click'))
|
|
166
|
+
lines.push(`Click buttons: ${caps.mouseClickButtons.join(', ') || 'none'}.`)
|
|
167
|
+
if (caps.mouseDragButtons && available.includes('mouse_drag'))
|
|
168
|
+
lines.push(`Drag buttons: ${caps.mouseDragButtons.join(', ') || 'none'}.`)
|
|
164
169
|
return lines.join(' ')
|
|
165
170
|
}
|
|
166
171
|
|
|
172
|
+
function availableActions(caps: ComputerUseCapabilities): ComputerUseAction['type'][] {
|
|
173
|
+
return actionSchema.options
|
|
174
|
+
.map((option) => option.shape.type.value)
|
|
175
|
+
.filter((action) => {
|
|
176
|
+
const required = requiredCapability(action)
|
|
177
|
+
return (
|
|
178
|
+
(required === null || caps[required] === true) &&
|
|
179
|
+
(caps.supportedActions === undefined || caps.supportedActions.includes(action)) &&
|
|
180
|
+
(action !== 'mouse_click' || caps.mouseClickButtons?.length !== 0) &&
|
|
181
|
+
(action !== 'mouse_drag' || caps.mouseDragButtons?.length !== 0)
|
|
182
|
+
)
|
|
183
|
+
})
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function hostModelSchema(caps: ComputerUseCapabilities): Record<string, unknown> {
|
|
187
|
+
const schema = structuredClone(modelInputSchema)
|
|
188
|
+
const actions = availableActions(caps)
|
|
189
|
+
// An unavailable host remains a diagnostic tool. Avoid invalid empty enums
|
|
190
|
+
// on provider wires; every execution is still refused before host access.
|
|
191
|
+
if (actions.length > 0) schema.properties.type.enum = actions
|
|
192
|
+
const buttons = new Set<string>()
|
|
193
|
+
if (actions.includes('mouse_click'))
|
|
194
|
+
for (const button of caps.mouseClickButtons ?? ['left', 'right', 'middle']) buttons.add(button)
|
|
195
|
+
if (actions.includes('mouse_drag'))
|
|
196
|
+
for (const button of caps.mouseDragButtons ?? ['left', 'right', 'middle']) buttons.add(button)
|
|
197
|
+
if (buttons.size > 0) schema.properties.button.enum = [...buttons]
|
|
198
|
+
return schema
|
|
199
|
+
}
|
|
200
|
+
|
|
167
201
|
function pointLabel(point: { readonly x: number; readonly y: number }): string {
|
|
168
202
|
return `(${point.x}, ${point.y})`
|
|
169
203
|
}
|
|
@@ -283,7 +317,7 @@ export function createComputerUseTool(host: ComputerUseHost): ToolDefinition<Act
|
|
|
283
317
|
name: COMPUTER_USE_TOOL_NAME,
|
|
284
318
|
description: buildDescription(host),
|
|
285
319
|
inputSchema: actionSchema,
|
|
286
|
-
modelInputSchema:
|
|
320
|
+
modelInputSchema: hostModelSchema(host.capabilities),
|
|
287
321
|
validationErrorHint:
|
|
288
322
|
'Action requirements: mouse_move needs "to"; mouse_click needs "at" and "button"; mouse_drag needs "from", "to", and "button"; scroll needs "at", "direction", and positive "amount"; type_text needs "text"; key needs "keys".',
|
|
289
323
|
category: 'custom',
|
|
@@ -310,6 +344,26 @@ export function createComputerUseTool(host: ComputerUseHost): ToolDefinition<Act
|
|
|
310
344
|
error: `computer_use: action "${input.type}" requires capability "${required}" which is not available on this host (displayServer=${host.capabilities.displayServer}).${host.capabilities.unavailableReason ? ` ${host.capabilities.unavailableReason} Do not retry; tell the user.` : ''}`,
|
|
311
345
|
}
|
|
312
346
|
}
|
|
347
|
+
if (!availableActions(host.capabilities).includes(input.type)) {
|
|
348
|
+
return {
|
|
349
|
+
success: false,
|
|
350
|
+
output: '',
|
|
351
|
+
error: `computer_use: action "${input.type}" is not supported on this host.`,
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
const buttons =
|
|
355
|
+
input.type === 'mouse_click'
|
|
356
|
+
? host.capabilities.mouseClickButtons
|
|
357
|
+
: input.type === 'mouse_drag'
|
|
358
|
+
? host.capabilities.mouseDragButtons
|
|
359
|
+
: undefined
|
|
360
|
+
if (buttons && 'button' in input && !buttons.includes(input.button)) {
|
|
361
|
+
return {
|
|
362
|
+
success: false,
|
|
363
|
+
output: '',
|
|
364
|
+
error: `computer_use: action "${input.type}" does not support button "${input.button}" on this host.`,
|
|
365
|
+
}
|
|
366
|
+
}
|
|
313
367
|
try {
|
|
314
368
|
const result = await host.execute(input as ComputerUseAction)
|
|
315
369
|
return resultToToolResult(result)
|