@namzu/sdk 36.0.0 → 38.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 +244 -0
- package/README.md +68 -41
- package/dist/bridge/a2a/mapper.d.ts.map +1 -1
- package/dist/bridge/a2a/mapper.js +4 -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 +16 -1
- 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/config/runtime.d.ts +16 -6
- package/dist/config/runtime.d.ts.map +1 -1
- package/dist/config/runtime.js +2 -0
- package/dist/config/runtime.js.map +1 -1
- package/dist/contracts/api.d.ts +1 -1
- package/dist/contracts/api.d.ts.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 +316 -46
- 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/prompt/coding-agent-doctrine.d.ts +2 -2
- package/dist/prompt/coding-agent-doctrine.d.ts.map +1 -1
- package/dist/prompt/coding-agent-doctrine.js +11 -5
- package/dist/prompt/coding-agent-doctrine.js.map +1 -1
- package/dist/provider/capabilities.d.ts +5 -1
- package/dist/provider/capabilities.d.ts.map +1 -1
- package/dist/provider/capabilities.js +24 -0
- package/dist/provider/capabilities.js.map +1 -1
- package/dist/provider/fallback.d.ts.map +1 -1
- package/dist/provider/fallback.js +6 -2
- package/dist/provider/fallback.js.map +1 -1
- package/dist/public-runtime.d.ts +4 -1
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +3 -1
- package/dist/public-runtime.js.map +1 -1
- package/dist/public-tools.d.ts +2 -1
- package/dist/public-tools.d.ts.map +1 -1
- package/dist/public-tools.js +2 -1
- package/dist/public-tools.js.map +1 -1
- package/dist/public-types.d.ts +2 -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 +2 -0
- package/dist/run/reporter.js.map +1 -1
- package/dist/run/token-budget.d.ts +12 -4
- package/dist/run/token-budget.d.ts.map +1 -1
- package/dist/run/token-budget.js +49 -14
- 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 +8 -3
- package/dist/runtime/query/executor.d.ts.map +1 -1
- package/dist/runtime/query/executor.js +94 -30
- package/dist/runtime/query/executor.js.map +1 -1
- package/dist/runtime/query/index.d.ts +7 -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 +12 -0
- package/dist/runtime/query/iteration/index.d.ts.map +1 -1
- package/dist/runtime/query/iteration/index.js +348 -38
- 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 +9 -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 -0
- package/dist/runtime/query/iteration/stream-turn.js.map +1 -1
- package/dist/runtime/query/observation-context.d.ts +10 -0
- package/dist/runtime/query/observation-context.d.ts.map +1 -0
- package/dist/runtime/query/observation-context.js +84 -0
- package/dist/runtime/query/observation-context.js.map +1 -0
- package/dist/runtime/query/request-context.d.ts +30 -0
- package/dist/runtime/query/request-context.d.ts.map +1 -0
- package/dist/runtime/query/request-context.js +76 -0
- package/dist/runtime/query/request-context.js.map +1 -0
- package/dist/runtime/query/request-rich-content.d.ts.map +1 -1
- package/dist/runtime/query/request-rich-content.js +6 -3
- package/dist/runtime/query/request-rich-content.js.map +1 -1
- package/dist/runtime/query/review-policy.d.ts +3 -0
- package/dist/runtime/query/review-policy.d.ts.map +1 -1
- package/dist/runtime/query/review-policy.js +4 -1
- package/dist/runtime/query/review-policy.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 +3 -0
- package/dist/runtime/query/tooling.d.ts.map +1 -1
- package/dist/runtime/query/tooling.js +5 -0
- package/dist/runtime/query/tooling.js.map +1 -1
- package/dist/sandbox/file-walk-program.d.ts.map +1 -1
- package/dist/sandbox/file-walk-program.js +8 -0
- package/dist/sandbox/file-walk-program.js.map +1 -1
- package/dist/sandbox/file-walk.d.ts.map +1 -1
- package/dist/sandbox/file-walk.js +9 -0
- package/dist/sandbox/file-walk.js.map +1 -1
- package/dist/scheduler/completion-inbox.d.ts.map +1 -1
- package/dist/scheduler/completion-inbox.js +3 -0
- 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/store/run/token-budget-disk.js +3 -0
- package/dist/store/run/token-budget-disk.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/edit.d.ts.map +1 -1
- package/dist/tools/builtins/edit.js +12 -26
- package/dist/tools/builtins/edit.js.map +1 -1
- package/dist/tools/builtins/file-write-result.d.ts +4 -0
- package/dist/tools/builtins/file-write-result.d.ts.map +1 -0
- package/dist/tools/builtins/file-write-result.js +72 -0
- package/dist/tools/builtins/file-write-result.js.map +1 -0
- package/dist/tools/builtins/glob.d.ts.map +1 -1
- package/dist/tools/builtins/glob.js +8 -1
- 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 +10 -0
- package/dist/tools/builtins/grep.js.map +1 -1
- package/dist/tools/builtins/job.d.ts.map +1 -1
- package/dist/tools/builtins/job.js +6 -0
- package/dist/tools/builtins/job.js.map +1 -1
- package/dist/tools/builtins/read-file.d.ts.map +1 -1
- package/dist/tools/builtins/read-file.js +10 -0
- package/dist/tools/builtins/read-file.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/builtins/write-file.d.ts.map +1 -1
- package/dist/tools/builtins/write-file.js +30 -44
- package/dist/tools/builtins/write-file.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/file-read-tracker.d.ts +4 -0
- package/dist/tools/file-read-tracker.d.ts.map +1 -0
- package/dist/tools/file-read-tracker.js +16 -0
- package/dist/tools/file-read-tracker.js.map +1 -0
- 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/tools/task/list.js +2 -2
- package/dist/tools/task/list.js.map +1 -1
- 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/plugin/index.d.ts +7 -0
- package/dist/types/plugin/index.d.ts.map +1 -1
- package/dist/types/plugin/index.js.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/chat.d.ts +4 -0
- package/dist/types/provider/chat.d.ts.map +1 -1
- package/dist/types/provider/config.d.ts +4 -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/provider/stream.d.ts +6 -0
- package/dist/types/provider/stream.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/config.d.ts +2 -0
- package/dist/types/run/config.d.ts.map +1 -1
- package/dist/types/run/events.d.ts +19 -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 +1 -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/types/tool/presentation.d.ts +4 -0
- package/dist/types/tool/presentation.d.ts.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 +4 -2
- package/src/bridge/a2a/mapper.ts +4 -0
- package/src/bridge/sse/mapper.ts +16 -1
- package/src/compaction/extractor.ts +21 -8
- package/src/compaction/manager.ts +11 -1
- package/src/compaction/verifier.ts +80 -18
- package/src/config/runtime.ts +2 -0
- package/src/contracts/api.ts +1 -0
- 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 +352 -54
- package/src/manager/run/persistence.ts +7 -0
- package/src/prompt/coding-agent-doctrine.ts +11 -5
- package/src/provider/capabilities.ts +41 -1
- package/src/provider/fallback.ts +9 -2
- package/src/public-runtime.ts +6 -0
- package/src/public-tools.ts +7 -1
- package/src/public-types.ts +7 -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 +2 -0
- package/src/run/token-budget.ts +55 -14
- package/src/run/workspace-fingerprint.ts +17 -8
- package/src/runtime/query/checkpoint.ts +96 -2
- package/src/runtime/query/executor.ts +100 -29
- package/src/runtime/query/index.ts +76 -16
- package/src/runtime/query/iteration/index.ts +405 -46
- 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 +9 -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 +15 -0
- package/src/runtime/query/observation-context.ts +86 -0
- package/src/runtime/query/request-context.ts +103 -0
- package/src/runtime/query/request-rich-content.ts +8 -3
- package/src/runtime/query/review-policy.ts +7 -1
- package/src/runtime/query/steering.ts +19 -2
- package/src/runtime/query/tool-call-budget.ts +115 -0
- package/src/runtime/query/tooling.ts +8 -0
- package/src/sandbox/file-walk-program.ts +8 -0
- package/src/sandbox/file-walk.ts +9 -0
- package/src/scheduler/completion-inbox.ts +3 -0
- 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/store/run/token-budget-disk.ts +3 -0
- package/src/tools/builtins/computer-use.ts +61 -7
- package/src/tools/builtins/edit.ts +12 -27
- package/src/tools/builtins/file-write-result.ts +84 -0
- package/src/tools/builtins/glob.ts +7 -1
- package/src/tools/builtins/grep.ts +10 -0
- package/src/tools/builtins/job.ts +8 -0
- package/src/tools/builtins/read-file.ts +10 -0
- package/src/tools/builtins/run-code.ts +24 -5
- package/src/tools/builtins/search-tools.ts +18 -3
- package/src/tools/builtins/write-file.ts +39 -44
- package/src/tools/defineTool.ts +5 -0
- package/src/tools/file-read-tracker.ts +16 -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/tools/task/list.ts +2 -2
- 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/plugin/index.ts +10 -0
- package/src/types/project/entity.ts +1 -0
- package/src/types/provider/chat.ts +2 -0
- package/src/types/provider/config.ts +4 -0
- package/src/types/provider/model.ts +4 -0
- package/src/types/provider/stream.ts +7 -0
- package/src/types/run/answer-review.ts +2 -0
- package/src/types/run/config.ts +2 -0
- package/src/types/run/events.ts +20 -0
- package/src/types/run/prepare-step.ts +19 -1
- package/src/types/sandbox/index.ts +1 -0
- package/src/types/structured-output/index.ts +15 -2
- package/src/types/tool/index.ts +16 -0
- package/src/types/tool/presentation.ts +4 -0
- package/src/utils/json-snapshot.ts +76 -0
|
@@ -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)
|
|
@@ -362,12 +362,18 @@ export const EditTool = defineTool({
|
|
|
362
362
|
return withFileMutationLock(lockKey, async () => {
|
|
363
363
|
if (context.sandbox) {
|
|
364
364
|
const buffer = await context.sandbox.readFile(parsed.data.path)
|
|
365
|
-
const
|
|
365
|
+
const content = buffer.toString('utf-8')
|
|
366
|
+
const seen = context.fileReadTracker?.fingerprint?.(parsed.data.path)
|
|
367
|
+
if (seen !== undefined && seen !== fingerprintContent(content)) {
|
|
368
|
+
return { success: false as const, output: '', error: staleFileError(parsed.data.path) }
|
|
369
|
+
}
|
|
370
|
+
const result = applyEdit(content, normalized.operations)
|
|
366
371
|
if (!result.success) {
|
|
367
372
|
return { success: false as const, output: '', error: result.error }
|
|
368
373
|
}
|
|
369
374
|
|
|
370
375
|
await context.sandbox.writeFile(parsed.data.path, result.content)
|
|
376
|
+
context.fileReadTracker?.recordRead(parsed.data.path, result.content)
|
|
371
377
|
return {
|
|
372
378
|
success: true as const,
|
|
373
379
|
output: `Edited ${parsed.data.path}: ${result.replacements} replacement(s) [sandboxed]`,
|
|
@@ -378,33 +384,12 @@ export const EditTool = defineTool({
|
|
|
378
384
|
const hostPath = filePath as string
|
|
379
385
|
const content = await readFile(hostPath, 'utf-8')
|
|
380
386
|
|
|
381
|
-
const
|
|
382
|
-
if (
|
|
383
|
-
|
|
384
|
-
// situations produce that, and the difference is the whole
|
|
385
|
-
// value of the fingerprint:
|
|
386
|
-
//
|
|
387
|
-
// The file is as the agent left it, and the anchor is simply
|
|
388
|
-
// wrong — "not found, match the whitespace exactly" is the
|
|
389
|
-
// right thing to say.
|
|
390
|
-
//
|
|
391
|
-
// Or the file moved after the read — a person in an editor,
|
|
392
|
-
// another process, a second agent — and the same message is a
|
|
393
|
-
// lie that sends the agent to re-check text that was never the
|
|
394
|
-
// problem, so it retries the identical edit against the same
|
|
395
|
-
// moved file.
|
|
396
|
-
//
|
|
397
|
-
// Deliberately NOT a gate on the successful path. An anchor
|
|
398
|
-
// that still matches uniquely is well defined however much
|
|
399
|
-
// changed elsewhere in the file, and refusing there would
|
|
400
|
-
// reject safe edits every time anyone touched an unrelated
|
|
401
|
-
// line.
|
|
402
|
-
const seen = context.fileReadTracker?.fingerprint?.(hostPath)
|
|
403
|
-
if (seen !== undefined && seen !== fingerprintContent(content)) {
|
|
404
|
-
return { success: false as const, output: '', error: staleFileError(hostPath) }
|
|
405
|
-
}
|
|
406
|
-
return { success: false as const, output: '', error: result.error }
|
|
387
|
+
const seen = context.fileReadTracker?.fingerprint?.(hostPath)
|
|
388
|
+
if (seen !== undefined && seen !== fingerprintContent(content)) {
|
|
389
|
+
return { success: false as const, output: '', error: staleFileError(hostPath) }
|
|
407
390
|
}
|
|
391
|
+
const result = applyEdit(content, normalized.operations)
|
|
392
|
+
if (!result.success) return { success: false as const, output: '', error: result.error }
|
|
408
393
|
|
|
409
394
|
// Temp file, fsync, rename — a reader sees the old body or the new
|
|
410
395
|
// one, never a half-written one. A plain `writeFile` that fails
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto'
|
|
2
|
+
import type { ToolResult } from '../../types/tool/index.js'
|
|
3
|
+
|
|
4
|
+
/** A final newline terminates a line; it does not add an empty line. */
|
|
5
|
+
function lines(text: string): string[] {
|
|
6
|
+
if (text === '') return []
|
|
7
|
+
const result = text.split('\n')
|
|
8
|
+
if (result.at(-1) === '') result.pop()
|
|
9
|
+
return result
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** null means the backend could not establish the previous state. */
|
|
13
|
+
export function fileWriteResult(
|
|
14
|
+
path: string,
|
|
15
|
+
before: string | undefined | null,
|
|
16
|
+
after: string,
|
|
17
|
+
sandboxed = false,
|
|
18
|
+
): ToolResult {
|
|
19
|
+
const operation =
|
|
20
|
+
before === null
|
|
21
|
+
? 'write'
|
|
22
|
+
: before === undefined
|
|
23
|
+
? 'create'
|
|
24
|
+
: before === after
|
|
25
|
+
? 'unchanged'
|
|
26
|
+
: 'replace'
|
|
27
|
+
const oldLines = lines(before ?? '')
|
|
28
|
+
const newLines = lines(after)
|
|
29
|
+
let start = 0
|
|
30
|
+
let end = 0
|
|
31
|
+
if (typeof before === 'string') {
|
|
32
|
+
while (
|
|
33
|
+
start < oldLines.length &&
|
|
34
|
+
start < newLines.length &&
|
|
35
|
+
oldLines[start] === newLines[start]
|
|
36
|
+
)
|
|
37
|
+
start++
|
|
38
|
+
while (
|
|
39
|
+
end < oldLines.length - start &&
|
|
40
|
+
end < newLines.length - start &&
|
|
41
|
+
oldLines[oldLines.length - end - 1] === newLines[newLines.length - end - 1]
|
|
42
|
+
)
|
|
43
|
+
end++
|
|
44
|
+
}
|
|
45
|
+
const removed = oldLines.slice(start, oldLines.length - end)
|
|
46
|
+
const added = newLines.slice(start, newLines.length - end)
|
|
47
|
+
const bytes = Buffer.byteLength(after, 'utf8')
|
|
48
|
+
const label =
|
|
49
|
+
operation === 'create'
|
|
50
|
+
? 'Created'
|
|
51
|
+
: operation === 'replace'
|
|
52
|
+
? 'Updated'
|
|
53
|
+
: operation === 'unchanged'
|
|
54
|
+
? 'Unchanged'
|
|
55
|
+
: 'Wrote'
|
|
56
|
+
const newlineChanged =
|
|
57
|
+
typeof before === 'string' && before.endsWith('\n') !== after.endsWith('\n')
|
|
58
|
+
const summary = `${label} ${path}${before === null ? '' : ` (+${added.length} -${removed.length})`}${newlineChanged ? ' · final newline changed' : ''}`
|
|
59
|
+
return {
|
|
60
|
+
success: true,
|
|
61
|
+
output: `${summary} · ${bytes} bytes`,
|
|
62
|
+
data: {
|
|
63
|
+
path,
|
|
64
|
+
size: after.length,
|
|
65
|
+
...(sandboxed ? { sandboxed: true } : {}),
|
|
66
|
+
fileChange: {
|
|
67
|
+
operation,
|
|
68
|
+
...(before === null
|
|
69
|
+
? {}
|
|
70
|
+
: {
|
|
71
|
+
preview: {
|
|
72
|
+
before: removed.length ? `${removed.join('\n')}\n` : '',
|
|
73
|
+
after: added.length ? `${added.join('\n')}\n` : '',
|
|
74
|
+
},
|
|
75
|
+
}),
|
|
76
|
+
bytes,
|
|
77
|
+
sha256: createHash('sha256').update(after, 'utf8').digest('hex'),
|
|
78
|
+
...(before === null
|
|
79
|
+
? {}
|
|
80
|
+
: { added: added.length, removed: removed.length, newlineChanged }),
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -68,7 +68,13 @@ export const GlobTool = defineTool({
|
|
|
68
68
|
timeoutMs: 15_000,
|
|
69
69
|
|
|
70
70
|
presentCall(input) {
|
|
71
|
-
|
|
71
|
+
if (typeof input.pattern !== 'string') return undefined
|
|
72
|
+
return {
|
|
73
|
+
kind: 'generic',
|
|
74
|
+
label: `Find ${input.pattern} in ${input.path ?? '.'}`,
|
|
75
|
+
presentation: 'activity',
|
|
76
|
+
activity: 'exploration',
|
|
77
|
+
}
|
|
72
78
|
},
|
|
73
79
|
|
|
74
80
|
async execute(input, context) {
|
|
@@ -98,6 +98,16 @@ export const GrepTool = defineTool({
|
|
|
98
98
|
readOnly: true,
|
|
99
99
|
destructive: false,
|
|
100
100
|
concurrencySafe: true,
|
|
101
|
+
|
|
102
|
+
presentCall(input) {
|
|
103
|
+
if (typeof input.pattern !== 'string') return undefined
|
|
104
|
+
return {
|
|
105
|
+
kind: 'generic',
|
|
106
|
+
label: `Search ${input.pattern} in ${input.path ?? '.'}`,
|
|
107
|
+
presentation: 'activity',
|
|
108
|
+
activity: 'exploration',
|
|
109
|
+
}
|
|
110
|
+
},
|
|
101
111
|
timeoutMs: 15_000,
|
|
102
112
|
|
|
103
113
|
async execute(input, context) {
|
|
@@ -54,6 +54,14 @@ export const JobTool = defineTool({
|
|
|
54
54
|
destructive: (input: JobInput) => input.action === 'kill',
|
|
55
55
|
concurrencySafe: true,
|
|
56
56
|
|
|
57
|
+
presentCall(input) {
|
|
58
|
+
const label =
|
|
59
|
+
input.action === 'list'
|
|
60
|
+
? 'List background jobs'
|
|
61
|
+
: `${input.action === 'kill' ? 'Stop background job' : 'Read background output'} · ${input.id ?? '(missing id)'}`
|
|
62
|
+
return { kind: 'generic', presentation: 'activity', label }
|
|
63
|
+
},
|
|
64
|
+
|
|
57
65
|
async execute(input, context) {
|
|
58
66
|
if (!context.backgroundJobs) {
|
|
59
67
|
return {
|
|
@@ -32,6 +32,16 @@ export const ReadFileTool = defineTool({
|
|
|
32
32
|
destructive: false,
|
|
33
33
|
concurrencySafe: true,
|
|
34
34
|
|
|
35
|
+
presentCall(input) {
|
|
36
|
+
if (typeof input.path !== 'string') return undefined
|
|
37
|
+
return {
|
|
38
|
+
kind: 'generic',
|
|
39
|
+
label: `Read ${input.path}`,
|
|
40
|
+
presentation: 'activity',
|
|
41
|
+
activity: 'exploration',
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
|
|
35
45
|
async execute(input, context) {
|
|
36
46
|
// Sandbox-aware: route through sandbox.readFile() when available
|
|
37
47
|
if (context.sandbox) {
|
|
@@ -49,6 +49,12 @@ export interface RunCodeToolOptions {
|
|
|
49
49
|
readonly runtime?: CodeRuntime
|
|
50
50
|
readonly timeoutMs?: number
|
|
51
51
|
readonly maxOutputBytes?: number
|
|
52
|
+
/**
|
|
53
|
+
* What a successful `call()` resolves to. Default: `text` (ToolResult.output).
|
|
54
|
+
* `structured` returns `{ output, data? }`, preserving JSON tool data for
|
|
55
|
+
* local filtering. Failures still reject; authority and dispatch are unchanged.
|
|
56
|
+
*/
|
|
57
|
+
readonly toolResultMode?: 'text' | 'structured'
|
|
52
58
|
}
|
|
53
59
|
|
|
54
60
|
const DEFAULT_TIMEOUT_MS = 30_000
|
|
@@ -59,8 +65,11 @@ export function buildRunCodeTool(options: RunCodeToolOptions = {}) {
|
|
|
59
65
|
|
|
60
66
|
return defineTool({
|
|
61
67
|
name: RUN_CODE_TOOL_NAME,
|
|
62
|
-
description:
|
|
63
|
-
|
|
68
|
+
description: `Runs a short JavaScript program that can call this run's own tools in a loop. Use it when the same tool would otherwise be called many times in a row — filtering, retrying, fanning out — and not for a single call. ${
|
|
69
|
+
options.toolResultMode === 'structured'
|
|
70
|
+
? 'Each successful call() returns { output: string, data?: JSON value }. Filter data locally and return only the needed result. Failed calls reject.'
|
|
71
|
+
: 'Each successful call() returns the tool output string. Failed calls reject.'
|
|
72
|
+
}`,
|
|
64
73
|
inputSchema,
|
|
65
74
|
category: 'custom',
|
|
66
75
|
permissions: [],
|
|
@@ -108,9 +117,19 @@ export function buildRunCodeTool(options: RunCodeToolOptions = {}) {
|
|
|
108
117
|
signal: operation.signal,
|
|
109
118
|
runtimeToolCallId: operation.runtimeToolCallId,
|
|
110
119
|
})
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
120
|
+
if (!toolResult.success) {
|
|
121
|
+
return { ok: false, error: toolResult.error ?? 'the tool failed' }
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
ok: true,
|
|
125
|
+
value:
|
|
126
|
+
options.toolResultMode === 'structured'
|
|
127
|
+
? {
|
|
128
|
+
output: toolResult.output,
|
|
129
|
+
...(toolResult.data !== undefined ? { data: toolResult.data } : {}),
|
|
130
|
+
}
|
|
131
|
+
: toolResult.output,
|
|
132
|
+
}
|
|
114
133
|
} catch (err) {
|
|
115
134
|
return {
|
|
116
135
|
ok: false,
|
|
@@ -38,8 +38,7 @@ export const SearchToolsTool = defineTool({
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
const allowed =
|
|
42
|
-
context.allowedTools && context.allowedTools.length > 0 ? new Set(context.allowedTools) : null
|
|
41
|
+
const allowed = context.allowedTools !== undefined ? new Set(context.allowedTools) : null
|
|
43
42
|
// `searchDeferred` returns a ranked list (score-descending), so slicing
|
|
44
43
|
// the head is a true top-k activation, not an arbitrary subset.
|
|
45
44
|
const ranked = context.toolRegistry
|
|
@@ -47,9 +46,25 @@ export const SearchToolsTool = defineTool({
|
|
|
47
46
|
.filter((tool) => !allowed || allowed.has(tool.name))
|
|
48
47
|
|
|
49
48
|
if (ranked.length === 0) {
|
|
49
|
+
const active = context.toolRegistry
|
|
50
|
+
.searchActive?.(input.query)
|
|
51
|
+
.filter(
|
|
52
|
+
(tool) =>
|
|
53
|
+
(!allowed || allowed.has(tool.name)) &&
|
|
54
|
+
context.toolRegistry?.getAvailability(tool.name) === 'active',
|
|
55
|
+
)
|
|
56
|
+
const activeReceipt =
|
|
57
|
+
active === undefined
|
|
58
|
+
? 'This registry cannot search active tools.'
|
|
59
|
+
: active.length === 0
|
|
60
|
+
? 'No matching active tools were found.'
|
|
61
|
+
: `Already active matching tools (up to ${ACTIVATION_TOP_K}):\n${active
|
|
62
|
+
.slice(0, ACTIVATION_TOP_K)
|
|
63
|
+
.map((tool) => `- ${tool.name}`)
|
|
64
|
+
.join('\n')}`
|
|
50
65
|
return {
|
|
51
66
|
success: true,
|
|
52
|
-
output: `No deferred tools matching "${input.query}".
|
|
67
|
+
output: `No deferred tools matching "${input.query}". ${activeReceipt}`,
|
|
53
68
|
}
|
|
54
69
|
}
|
|
55
70
|
|
|
@@ -7,6 +7,7 @@ import { resolveWithinAnyReal, toolRoots } from '../paths.js'
|
|
|
7
7
|
import { atomicWriteFile } from './atomic-write-file.js'
|
|
8
8
|
import { fingerprintContent, staleFileError } from './content-fingerprint.js'
|
|
9
9
|
import { withFileMutationLock } from './file-mutation-lock.js'
|
|
10
|
+
import { fileWriteResult } from './file-write-result.js'
|
|
10
11
|
|
|
11
12
|
const inputSchema = z
|
|
12
13
|
.object({
|
|
@@ -81,40 +82,35 @@ export const WriteFileTool = defineTool({
|
|
|
81
82
|
destructive: true,
|
|
82
83
|
concurrencySafe: false,
|
|
83
84
|
|
|
84
|
-
|
|
85
|
-
* The whole file body, described by the tool.
|
|
86
|
-
*
|
|
87
|
-
* A `diff` with an EMPTY `before`, which is what a write actually is:
|
|
88
|
-
* whatever was there is gone and this is what replaces it. `edit`
|
|
89
|
-
* declines to do that for an insert — there, an empty `before` would
|
|
90
|
-
* claim the whole file was added and it was not. Here it is true.
|
|
91
|
-
*
|
|
92
|
-
* A host with nothing to contrast against renders the `after` plainly
|
|
93
|
-
* rather than as `+` lines, which is the row a reader wants: they are
|
|
94
|
-
* approving a file, not reviewing a patch.
|
|
95
|
-
*/
|
|
85
|
+
// Input alone cannot establish whether this replaces an existing file.
|
|
96
86
|
presentCall(input: WriteInput) {
|
|
97
|
-
|
|
98
|
-
if (typeof content !== 'string') return undefined
|
|
99
|
-
return {
|
|
100
|
-
kind: 'diff' as const,
|
|
101
|
-
...(input.path ? { path: input.path } : {}),
|
|
102
|
-
before: '',
|
|
103
|
-
after: content,
|
|
104
|
-
}
|
|
87
|
+
return { kind: 'generic' as const, label: input.path }
|
|
105
88
|
},
|
|
106
89
|
|
|
107
|
-
/**
|
|
108
|
-
* A label, deliberately — which is what suppresses the detail block.
|
|
109
|
-
*
|
|
110
|
-
* The content was already shown under the CALL, where the user could
|
|
111
|
-
* act on it. Repeating it under the result doubles the longest rows in
|
|
112
|
-
* the transcript to say nothing new. A host used to decide this by
|
|
113
|
-
* matching `name === 'write' || name === 'edit'`; it is the tool's to
|
|
114
|
-
* say, and now it says it.
|
|
115
|
-
*/
|
|
90
|
+
/** The receipt names the observed operation; failures retain their error output. */
|
|
116
91
|
presentResult(_input: WriteInput, result: ToolResult) {
|
|
117
|
-
|
|
92
|
+
const data = result.data as
|
|
93
|
+
| { fileChange?: { preview?: { before?: unknown; after?: unknown } } }
|
|
94
|
+
| undefined
|
|
95
|
+
const preview = data?.fileChange?.preview
|
|
96
|
+
if (
|
|
97
|
+
result.success &&
|
|
98
|
+
typeof preview?.before === 'string' &&
|
|
99
|
+
typeof preview.after === 'string'
|
|
100
|
+
) {
|
|
101
|
+
return {
|
|
102
|
+
kind: 'diff' as const,
|
|
103
|
+
path: _input.path,
|
|
104
|
+
label: result.output?.split('\n')[0],
|
|
105
|
+
before: preview.before,
|
|
106
|
+
after: preview.after,
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
kind: 'generic' as const,
|
|
111
|
+
label: result.output?.split('\n')[0] ?? '',
|
|
112
|
+
...(result.success ? { presentation: 'activity' as const } : {}),
|
|
113
|
+
}
|
|
118
114
|
},
|
|
119
115
|
|
|
120
116
|
async execute(input: WriteInput, context) {
|
|
@@ -146,7 +142,7 @@ export const WriteFileTool = defineTool({
|
|
|
146
142
|
return withFileMutationLock(lockKey, async () => {
|
|
147
143
|
if (context.sandbox) {
|
|
148
144
|
const current = await readSandboxFileIfPresent(context, valid.path)
|
|
149
|
-
if (current !== undefined) {
|
|
145
|
+
if (current !== undefined && current !== null) {
|
|
150
146
|
const guard = enforceFreshOverwrite(context, valid.path, current.toString('utf-8'))
|
|
151
147
|
if (guard) return guard
|
|
152
148
|
}
|
|
@@ -155,11 +151,12 @@ export const WriteFileTool = defineTool({
|
|
|
155
151
|
// the boolean would leave an older content fingerprint in place and
|
|
156
152
|
// make the next same-run write refuse its own predecessor as drift.
|
|
157
153
|
context.fileReadTracker?.recordRead(valid.path, content)
|
|
158
|
-
return
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
154
|
+
return fileWriteResult(
|
|
155
|
+
valid.path,
|
|
156
|
+
current === null ? null : current?.toString('utf-8'),
|
|
157
|
+
content,
|
|
158
|
+
true,
|
|
159
|
+
)
|
|
163
160
|
}
|
|
164
161
|
|
|
165
162
|
const hostPath = filePath as string
|
|
@@ -176,11 +173,7 @@ export const WriteFileTool = defineTool({
|
|
|
176
173
|
await atomicWriteFile(hostPath, content)
|
|
177
174
|
context.fileReadTracker?.recordRead(hostPath, content)
|
|
178
175
|
|
|
179
|
-
return
|
|
180
|
-
success: true as const,
|
|
181
|
-
output: `File written successfully: ${hostPath} (${content.length} chars)`,
|
|
182
|
-
data: { path: hostPath, size: content.length },
|
|
183
|
-
}
|
|
176
|
+
return fileWriteResult(hostPath, current, content)
|
|
184
177
|
})
|
|
185
178
|
},
|
|
186
179
|
})
|
|
@@ -237,14 +230,16 @@ function isMissingFileError(error: unknown): boolean {
|
|
|
237
230
|
async function readSandboxFileIfPresent(
|
|
238
231
|
context: ToolContext,
|
|
239
232
|
path: string,
|
|
240
|
-
): Promise<Buffer | undefined> {
|
|
233
|
+
): Promise<Buffer | undefined | null> {
|
|
241
234
|
if (!context.sandbox) return undefined
|
|
242
235
|
try {
|
|
243
236
|
return await context.sandbox.readFile(path)
|
|
244
|
-
} catch {
|
|
237
|
+
} catch (error) {
|
|
238
|
+
if (isMissingFileError(error)) return undefined
|
|
245
239
|
// `Sandbox` currently has no typed missing-file result. Preserve the
|
|
246
240
|
// existing create behavior for all backends; when a read succeeds, the
|
|
247
241
|
// exact body above is still a real admission-time freshness check.
|
|
248
|
-
|
|
242
|
+
// An untyped read failure does not prove that the target was absent.
|
|
243
|
+
return null
|
|
249
244
|
}
|
|
250
245
|
}
|
package/src/tools/defineTool.ts
CHANGED
|
@@ -20,6 +20,8 @@ export interface DefineToolOptions<S extends z.ZodType> {
|
|
|
20
20
|
readOnly: boolean
|
|
21
21
|
destructive: boolean | ((input: z.infer<S>) => boolean)
|
|
22
22
|
concurrencySafe: boolean
|
|
23
|
+
/** Batch ordering boundary; see {@link ToolDefinition.executionBarrier}. */
|
|
24
|
+
executionBarrier?: boolean
|
|
23
25
|
tier?: string
|
|
24
26
|
/**
|
|
25
27
|
* How this tool's call and result should be shown; see
|
|
@@ -81,6 +83,9 @@ export function defineTool<S extends z.ZodType>(
|
|
|
81
83
|
...(options.presentResult ? { presentResult: options.presentResult } : {}),
|
|
82
84
|
...(options.outputSchema !== undefined ? { outputSchema: options.outputSchema } : {}),
|
|
83
85
|
...(options.terminal !== undefined ? { terminal: options.terminal } : {}),
|
|
86
|
+
...(options.executionBarrier !== undefined
|
|
87
|
+
? { executionBarrier: options.executionBarrier }
|
|
88
|
+
: {}),
|
|
84
89
|
category: options.category,
|
|
85
90
|
permissions: options.permissions,
|
|
86
91
|
isReadOnly: () => options.readOnly,
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { FileReadTracker } from '../types/tool/index.js'
|
|
2
|
+
import { fingerprintContent } from './builtins/content-fingerprint.js'
|
|
3
|
+
|
|
4
|
+
/** Host-owned observation ledger. Share only across turns of the same conversation and filesystem. */
|
|
5
|
+
export function createFileReadTracker(): FileReadTracker {
|
|
6
|
+
const paths = new Set<string>()
|
|
7
|
+
const fingerprints = new Map<string, string>()
|
|
8
|
+
return {
|
|
9
|
+
recordRead(key, content) {
|
|
10
|
+
paths.add(key)
|
|
11
|
+
if (content !== undefined) fingerprints.set(key, fingerprintContent(content))
|
|
12
|
+
},
|
|
13
|
+
hasRead: (key) => paths.has(key),
|
|
14
|
+
fingerprint: (key) => fingerprints.get(key),
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
import type { MemoryStore } from '../../types/memory/index.js'
|
|
3
|
+
import type { ToolDefinition } from '../../types/tool/index.js'
|
|
4
|
+
import { asMemoryId } from '../../utils/id.js'
|
|
5
|
+
import { defineTool } from '../defineTool.js'
|
|
6
|
+
|
|
7
|
+
export function buildDeleteMemoryTool(store: MemoryStore): ToolDefinition {
|
|
8
|
+
return defineTool({
|
|
9
|
+
name: 'delete_memory',
|
|
10
|
+
description:
|
|
11
|
+
'Permanently delete a stored memory by ID. Use update_memory with status archived when the record should remain available for inspection. Deletion does not erase past conversation transcripts.',
|
|
12
|
+
inputSchema: z.object({
|
|
13
|
+
id: z.string().describe('Memory ID to permanently delete'),
|
|
14
|
+
}),
|
|
15
|
+
category: 'custom',
|
|
16
|
+
permissions: [],
|
|
17
|
+
readOnly: false,
|
|
18
|
+
destructive: true,
|
|
19
|
+
concurrencySafe: true,
|
|
20
|
+
async execute({ id }) {
|
|
21
|
+
const removed = await store.delete(asMemoryId(id))
|
|
22
|
+
return {
|
|
23
|
+
success: removed,
|
|
24
|
+
output: removed ? `Memory deleted: ${id}.` : `Memory ${id} not found.`,
|
|
25
|
+
...(removed ? {} : { error: 'Memory not found' }),
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
})
|
|
29
|
+
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { MemoryIndex, MemoryStore } from '../../types/memory/index.js'
|
|
2
2
|
import type { ToolDefinition } from '../../types/tool/index.js'
|
|
3
|
+
import { buildDeleteMemoryTool } from './delete.js'
|
|
3
4
|
import { buildReadMemoryTool } from './read.js'
|
|
4
5
|
import { buildSaveMemoryTool } from './save.js'
|
|
5
6
|
import { buildSearchMemoryTool, buildStoreSearchMemoryTool } from './search.js'
|
|
7
|
+
import { buildUpdateMemoryTool } from './update.js'
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
10
|
* Build memory tools over one authoritative store.
|
|
@@ -28,9 +30,13 @@ export function buildMemoryTools(store: MemoryStore, index?: MemoryIndex): ToolD
|
|
|
28
30
|
index ? buildSearchMemoryTool(index) : buildStoreSearchMemoryTool(store),
|
|
29
31
|
buildReadMemoryTool(store),
|
|
30
32
|
buildSaveMemoryTool(store),
|
|
33
|
+
buildUpdateMemoryTool(store),
|
|
34
|
+
buildDeleteMemoryTool(store),
|
|
31
35
|
]
|
|
32
36
|
}
|
|
33
37
|
|
|
34
38
|
export { buildSearchMemoryTool } from './search.js'
|
|
35
39
|
export { buildReadMemoryTool } from './read.js'
|
|
36
40
|
export { buildSaveMemoryTool } from './save.js'
|
|
41
|
+
export { buildUpdateMemoryTool } from './update.js'
|
|
42
|
+
export { buildDeleteMemoryTool } from './delete.js'
|
package/src/tools/memory/save.ts
CHANGED
|
@@ -6,7 +6,8 @@ import { defineTool } from '../defineTool.js'
|
|
|
6
6
|
export function buildSaveMemoryTool(store: MemoryStore): ToolDefinition {
|
|
7
7
|
return defineTool({
|
|
8
8
|
name: 'save_memory',
|
|
9
|
-
description:
|
|
9
|
+
description:
|
|
10
|
+
'Save a new historical claim for future reference. Include the actual useful fact and its evidence in the summary and content. For corrections to an existing record use update_memory instead of creating contradictory duplicates.',
|
|
10
11
|
inputSchema: z.object({
|
|
11
12
|
title: z.string().min(1).describe('Short descriptive title'),
|
|
12
13
|
summary: z.string().min(1).describe('Brief summary (1-2 sentences)'),
|
|
@@ -18,12 +19,13 @@ export function buildSaveMemoryTool(store: MemoryStore): ToolDefinition {
|
|
|
18
19
|
readOnly: false,
|
|
19
20
|
destructive: false,
|
|
20
21
|
concurrencySafe: true,
|
|
21
|
-
async execute({ title, summary, content, tags }) {
|
|
22
|
+
async execute({ title, summary, content, tags }, context) {
|
|
22
23
|
const { entry } = await store.create({
|
|
23
24
|
title,
|
|
24
25
|
summary,
|
|
25
26
|
content,
|
|
26
27
|
tags,
|
|
28
|
+
metadata: { source: 'agent-memory', runId: context.runId },
|
|
27
29
|
})
|
|
28
30
|
|
|
29
31
|
return {
|